rssbridge.guiguishow.info Open in urlscan Pro
2001:41d0:404:200::174d  Public Scan

URL: https://rssbridge.guiguishow.info/
Submission: On December 26 via api from US — Scanned from US

Form analysis 1 forms found in the DOM

GET https://www.guiguishow.info

<form id="searchform" action="https://www.guiguishow.info" method="get">
  <input type="text" id="searchinput" name="s" class="searchinput" value="search" onfocus="if (this.value == 'search') {this.value = '';}" onblur="if (this.value == '') {this.value = 'search';}">
  <input type="submit" id="searchsubmit" class="button" value="">
</form>

Text Content

lalahop


GUIGUI'S SHOW





 * ACCUEIL
 * Mon Shaarli
 * TLS
 * Mentions légales

   
 * flux rss




MON SHAARLI : 2 ANS PLUS TARD

Posté le 8 mars 2015 à 20h42 par GuiGui



Cela fait un peu plus de 2 ans que j'utilise l'application web shaarli (« The
personal, minimalist, super-fast, no-database delicious clone », un gestionnaire
de favoris en ligne et plus que ça). Il est temps de faire un point.

D'abord, il faut remarquer que mon shaarli est devenu mon principal support
d'expression sur le web, loin devant ce blog. Ainsi, je vous conseille d'aller y
faire un tour, voire de suivre le flux RSS. Je shaarli systématiquement mes
billets de blog donc il est inutile de suivre les deux flux RSS : suivez
shaarli. 😀

Ensuite, voyons si shaarli m'a aidé à remplir les objectifs que je m'étais fixés
et qui sont exposés dans le billet suivant : Mon Shaarli :

 * Partager beaucoup plus de documentation, d'avis et de retours d'expérience :
   949 shaarlis en un peu plus de 2 ans, je pense que cet objectif est atteint
   même si des shaarlis pointent vers du divertissement. Je suis au maximum en
   ce qui concerne la documentation et les retours d'expérience : je partage
   toutes les technos/techniques/bonnes_documentations que je
   découvre/manipule/mets_en_production. De plus, j'ai entraîné (à minima 😀 )
   Johndescs et b4n qui, tout comme moi, documentent/font_circuler plus de
   choses qu'avant.
 * Réactions à l'actualité et aux déclarations de ceux qui ont le droit au
   chapitre par copinage et tradition : objectif beaucoup moins bien atteint. Je
   m'interroge toujours autant sur la pertinence de réagir à des effets
   d'annonce et/ou à des projets futurs encore flous de type "machin a dit que
   ceci ou cela sera peut-être fait", "tel texte de loi pourrait émerger",… Pour
   moi c'est entre nécessité de réagir pour ne pas les laisser faire n'importe
   quoi sous couvert de notre accord tacite et contribution inutile à un bruit
   ambiant totalement stupide et contre-productif…

Enfin, la seule ombre au tableau est que mon shaarli reste 4 fois moins
fréquenté que ce blog. Je ne sais pas si c'est la structure d'un shaarli qui ne
plaît pas aux moteurs de recherche ou si c'est le fait d'avoir utilisé un
domaine différent (qui fait que la réputation attribuée par les algorithmes
repart de zéro). Non pas que j'ai envie d'être une vedette du web ou que sais-je
mais juste que je me demande comment diffuser toujours plus les
infos/contenus/savoirs à toujours plus de personnes : ai-je fait le maximum pour
que mon contenu atteigne toutes les personnes qui pourraient être intéressées ?

En conclusion : viendez sur mon shaarli car ce blog, même s'il est loin de
disparaître, est secondaire dans mes supports d'expression sur Internet. Je vous
encourage vivement à installer votre propre instance de shaarli et à contribuer
à diffuser savoir/avis/retour_d'expérience/bonne_humeur/que_sais-je. C'est juste
vital. Un gros GG à Sebsauvage, l'auteur de ce logiciel. GG pour une application
totalement fonctionnelle qui juste marche sans prendre la tête et GG pour un
support d'expression qui libère, en tout cas, qui me correspond et me libère.
\o/


Catégorie: Divers, Humeur / Tags: aucun tag / 2 commentaires


TP MOBILITÉ ET RÉSEAUX SANS FIL : RÉSEAU SANS FIL SÉCURISÉ ET MONITORÉ +
MOBILITÉ IPV6

Posté le 12 octobre 2016 à 14h13 par GuiGui



Cet article relate la mise en œuvre d'un réseau Wi-Fi sécurisé et monitoré du
type de ce que l'on peut trouver dans une société commerciale, une université ou
une association. Pour un point d'accès Wi-Fi ouvert à domicile, je recommande
plutôt cet excellent tutoriel : Mise en place d'un réseau Wi-Fi ouvert - Emile
(iMil) Heitor.

Même si cette mise en œuvre se situe dans un cadre scolaire (« bouh c'est nul,
on ne fait pas comme ça en vrai ! » diront certains), je pense qu'elle vaut la
peine d'être partagée et d'être lue car les technos étudiées (RADIUS, 802.1X,
radvd/dhcpv6, etc.) sont intéressantes et que les problématiques posées sont
celles que l'on rencontre dans de vrais déploiements : RADIUS, limites de
l'accounting RADIUS dans un réseau Wi-Fi 802.1X, problématiques légales autour
des données de connexion, cohabitation entre SLAAC et DHCPv6, etc.

Ce travail a été réalisé avec Hamza Hmama.

Ce travail datant d'il y a 3 ans, je l'ai actualisé avant publication, quand
j'ai estimé que c'était nécessaire. Par exemple, des situations ont évolué
(comme umip), j'ai un peu de recul, etc.

Je remercie Christian pour le prêt longue durée d'un WRT54GL. 🙂 Merci à bcollet
pour le don d'un Cisco Aironet 1120B. 🙂


TABLE DES MATIÈRES

 * Table des matières
 * Énoncé
 * Choix
   * Machine routeur / passerelle
   * Point d'accès Wi-Fi / AP
   * Portail captif
   * Utiliser le portail captif en tant que proxy RADIUS ?
   * SSIDs
   * Adressage IP
     * IPv6
       * Allocation
       * Autoconfiguration stateless ou autoconfiguration stateful ?
     * IPv4
   * Gestion du RADIUS
   * Mécanismes d'authentification 802.1X
   * Supervision et métrologie
     * Supervision
     * Métrologie
     * Typologie des flux réseaux
 * Architecture déployée
   * VLANs
 * Données de connexion
   * Généralités
   * Authentification UAM
   * Authentification 802.1X
   * Outro
 * Page d'administration
 * Mobilité IPv6
   * Kézako ?
   * Choix de l'implémentation
   * Quand la mobilité IP rencontre BCP38
 * Mise en œuvre
   * Configurer un point d'accès Cisco Aironet 1120B
   * Configurer un point d'accès Linksys WRT54GL avec OpenWRT
   * Installer un système Debian GNU/Linux sur une clé USB bootable
   * Configuration de base de la passerelle
     * Virer avahi
     * NTP
     * IPv6
     * /etc/network/interfaces
     * Activer l'IP forward
     * radvd
     * DHCP
       * DHCPv4
       * DHCPv6
     * NAPT
   * Tester
   * Authentification 802.1X
     * (Free)RADIUS
     * 802.1X sur un AP Cisco Aironet
     * 802.1X sur un AP WRT54GL avec OpenWRT
     * Tester
     * Stocker les utilisateurs de notre hotspot dans MySQL
     * Alléger et sécuriser freeRADIUS
   * PepperSpot
     * Faire le ménage
     * Lire le manuel
       * Remarque sur l'IPv6 forwarding et l'autoconfiguration IPv6 (section
         1.1.3)
       * Remarques sur le serveur web
       * Remarques sur les règles de filtrage
       * Remarque sur la configuration
       * Remarques sur le lancement automatique
   * Données de connexion
     * Accounting RADIUS
       * Sur un point d'accès Cisco Aironet 1120B
       * Sur un point d'accès WRT54GL avec OpenWRT
       * Actualisation fréquente…
       * … et disparition subite d'un client Wi-Fi
       * Comment ajouter un attribut de réponse dans une réponse RADIUS ?
       * Attributs de réponse et subtilité EAP-TTLS
       * Stockage de l'IPv6 des tickets d'accounting
       * Ménage régulier
       * Outro
     * Logs DHCP
     * Journaliser les associations MAC<->IP
   * Administration, supervision, types de flux
     * Supervision
     * Métrologie
     * Typologie des flux réseaux
     * Zone d'administration
     * Gestion de la base de données RADIUS
     * SNMP
       * SNMPd sur notre Cisco Aironet
       * SNMPd sur notre WRT54GL avec OpenWRT
     * Page d'administration
   * Mobilité IPv6
     * Côté noyau
     * Côté userland
 * Démonstrations
   * Ajouter un utilisateur autorisé à se connecter à notre hotspot
   * Authentification via le portail captif
     * IPv4
     * IPv6
   * Authentification 802.1X
   * Accounting RADIUS
   * Administration & supervision
   * Mobilité IPv6




ÉNONCÉ

Malheureusement, j'ai jeté l'énoncé à la poubelle lors d'un déménagement et je
n'en ai pas gardé une copie numérique. Mais, en gros, il nous a été demandé de :

 * Mettre en place un hotspot Wi-Fi avec une authentification UAM (un portail
   captif, quoi) et une authentification 802.1X, similaire aux réseaux Wi-Fi
   universitaire OSIRIS et OSIRIS-sec déployés par la direction informatique de
   l'université sur tout le campus ;
 * Chaque client Wi-Fi doit avoir une connectivité IPv4 et IPv6 ;
 * Produire des logs et mettre en place une solution de supervision qui fait
   remonter des informations pertinentes (état de la machine passerelle, état
   des liaisons, trafic, types de trafic, etc.) ;
 * Aucune solution de filtrage (de sites web, de ports, de noms de domaine,…) ou
   de traçabilité (qui a consulté telle ressource à telle heure) n'a été
   demandée. En conséquence, nous n'avons installé aucun serveur proxy ou autres
   outils ;
 * Configurer un mobile node IPv6 sur une machine cliente de notre point d'accès
   Wi-Fi ;
 * Nous verrons tout au long de cet article que des consignes et des
   recommandations informelles ont été ajoutées par le prof' tout au long de ce
   TP.

Ce sujet est celui de Thomas Noël, de l'université de Strasbourg, dans le cadre
du cours « Mobilité et réseaux sans fil ».


CHOIX

Panorama des choix que nous avons faits.

MACHINE ROUTEUR / PASSERELLE

Il s'agit de la machine qui fait la jonction entre le réseau filaire et les
réseaux sans fil et sur laquelle nous allons installer le portail captif, le
serveur RADIUS, stocker les données de connexion, etc.

Afin de pouvoir avancer ce projet durant les vacances universitaires de
Toussaint, d'être indépendants des séances de TP et de la disponibilité de la
salle de TP, nous avons fait le choix de travailler avec l'un de nos ordinateurs
personnels. Il s'agit d'un ordinateur portable standard. Le handicap principal
est qu'il est équipé d'une seule prise réseau, nous y reviendrons.

Comme il était hors de question de reformater cet ordinateur pour créer une
partition dédiée à ce projet (manque d'espace), ou d'installer tout et n'importe
quoi sur notre système stable que nous utilisons au quotidien, ou d'utiliser la
virtualisation qui peut parfois se montrer pénible lorsqu'il s'agit de prolonger
des VLANs à l'intérieur de la machine virtuelle, nous avons décidé d'installer
un système GNU/Linux Debian testing dédié à ce projet sur une clé USB bootable.

POINT D'ACCÈS WI-FI / AP

Là aussi, afin de pouvoir avancer ce projet durant les vacances universitaires
de Toussaint, d'être indépendants des séances de TP et de la disponibilité de la
salle de TP (dans laquelle étaient stockées les AP 😉 ) et des points d'accès
Wi-Fi eux-mêmes, nous avons dû chercher un moyen de nous émanciper des bornes
Cisco fournies par l'université.

Dans un premier temps, nous avons utilisé hostapd, un logiciel libre qui permet
la création de points d'accès Wi-Fi (en mode infrastructure) sur un ordinateur
équipé d'une carte réseau compatible. Nous avons passé du temps à mettre en
place un SSID sécurisé (802.1X) fonctionnel avant de nous rendre compte que la
carte réseau Wi-Fi (une Atheros AR9285 😉 ) de notre machine personnelle
supporte la création d'un seul SSID tout au plus en simultané.

Note : si les drivers sont compatibles, il est possible de savoir combien de
SSID une carte réseau peut gérer dans tel mode en utilisant la commande « iw
list » et en regardant « Supported interface modes » et « valid interface
combinations » dans la sortie. Pour les tutoriels qui vont bien, voir : création
d'un point d'accès Wi-Fi sur son ordinateur avec hostapd dans la doc' Ubuntu et
Multiple SSIDs with hostapd.

Finalement, notre choix s'est porté sur un point d'accès Cisco Aironet 1120B de
récupération. Bien que ce modèle présente quelques limitations (802.11b
uniquement, pas de support de WPA2 ni de CCMP, notamment), il est amplement
suffisant pour mener à bien ce projet universitaire.

PORTAIL CAPTIF

Avant de rechercher les différents portails captifs existants, nous avons établi
les critères d'évaluation et de comparaison suivants (du plus important au moins
important) :

 * Il doit être libre et gratuit ;
 * Il doit être basé sur GNU/Linux ou *BSD ou être un logiciel qui fonctionne
   sur un système d'exploitation faisant partie de ces deux familles ;
 * Il doit gérer IPv6 avec les mêmes fonctionnalités qu'IPv4 et notamment en ce
   qui concerne la redirection et l'authentification. De 0 (pire) à 2 (meilleur)
   :
   * 0 : aucune prise en charge d'IPv6 ;
   * 1 : prise en charge expérimentale ou partielle (exemple : pas de
     redirection vers le portail captif en IPv6 donc obligation de
     s'authentifier en IPv4) ;
   * 2 : prise en charge complète d'IPv6, y compris pour effectuer la
     redirection vers le portail captif.
 * Il doit être compatible avec notre machine : nous n'avons pas de machine à
   consacrer à l'installation d'une solution ni l'envie de nous coltiner les
   problèmes d'interaction avec les fonctions avancées des réseaux que l'on
   retrouve avec les machines virtuelles. En conséquence, la solution retenue
   doit être bootable sur une clé USB ou être compatible Debian. « Oui » : la
   solution répond à cette exigence, « Non » sinon ;
 * Il doit être maintenu et documenté. De 0 (pire) à 2 (meilleur) :
   * 0 : la solution est un projet abandonné et peu documenté ;
   * 1 : la solution est suffisamment documentée et le projet est maintenu de
     manière approximative ;
   * 2 : le projet est encore maintenu et toute la documentation nécessaire est
     à disposition ;
 * Il doit être facile à administrer après la configuration initiale. « Oui » :
   la solution dispose d'une interface web de configuration qui donne accès à
   tous les paramètres nécessaires pour mener à bien ce projet ainsi qu'à des
   stats pertinentes, « Non » sinon.

Lors d'une première passe, nous avons éliminé les solutions suivantes car elles
ne sont pas gratuites ou pas libres : Air Marshal, Net4Guest, Aradial,
Cloudessa, Cloud4Wi, DNS Redirector, FirstSpot, LogiSense, Amazingports, Ecnex,
Untangle.

Nous avons appliqué nos critères précédemment énoncés sur les solutions
restantes. En voici une synthèse :

Nom IPv6 Compatibilité Documentation Facilité d'administration ALCASAR Non **
Oui Chillispot Oui Non Coovachili *



** Non M0n0wall Non * Oui PacketFence Oui ** Oui PepperSpot ** Oui ** Non
PfSense * Non ** Oui Talweg Oui Non Wi-Fidog, NoCat Non * Non Zentyal Non * Oui
Zeroshell Non ** Oui

On constate que seulement trois portails captifs se démarquent par une prise en
charge (parfois minimale) d'IPv6 : Coovachilli, PfSense et PepperSpot.
Coovachilli et PfSense disposent toutefois d'une prise en charge expérimentale
incomplète : il n'y a pas de redirection pour authentification en IPv6.

La seule limite que nous avons trouvée à PepperSpot est l'utilisation d'une
fenêtre pop-up qui doit rester ouverte pour que la machine reste authentifiée
sur le réseau. Cela n'est pas pratique avec un ordiphone.

En conclusion, nous avons choisi le portail captif PepperSpot.

Si c'était aujourd'hui (en octobre 2016), je conseillerais de regarder
attentivement du côté de PfSense qui est une solution tout intégrée qui a l'air
d'avoir bien évolué depuis ce travail. Il n'était pas stable à l'époque (genre
tes paramètres pouvaient disparaître alors que c'était tout bien configuré lors
de la dernière utilisation), il l'est devenu, semble-t-il. En revanche, je ne
sais pas s'il gère la redirection pour authentification en IPv6 ou s'il ne gère
toujours pas cela.

Toujours en 2016, avec du recul, je fais remarquer qu'une solution toute
intégrée est moins susceptible de vous faire progresser qu'une solution où il
faudra installer, configurer et comprendre chaque composant qui constitue
l'architecture finale. Dans un TP universitaire, j'ai tendance à penser qu'on
doit tout décortiquer et comprendre, quitte à présenter une solution moins jolie
visuellement ou moins ergonomique.

UTILISER LE PORTAIL CAPTIF EN TANT QUE PROXY RADIUS ?

Une connexion sécurisée (802.1X) à notre hotspot se fera via un autre SSID et
l'authentification ne passera pas par PepperSpot qui peut être un proxy RADIUS.

Nous n'utiliserons pas cette fonctionnalité : notre point d'accès Cisco
contactera directement notre serveur RADIUS pour authentifier les clients,
principalement car l'utilisation d'un proxy RADIUS ajoute de la complexité
inutile donc un risque de panne supplémentaire qui peut s'avérer difficile à
débugger). Sans compter que bien séparer les deux réseaux, y compris pour
l'authentification, nous permet de mieux répartir le travail entre nous : on
installe le RADIUS et chacun de nous peut travailler sur l'un des SSID.

SSIDS

Ce n'est pas le plus important donc nous avons fait dans la simplicité (l'idée
étant aussi d'éviter les doublons lors de la séance de TP dédiée à l'évaluation)
:

 * SSID pour le réseau avec le portail captif : TESTAP ;
 * SSID pour le réseau avec l'authentification 802.1X : TESTAP-sec.

ADRESSAGE IP

IPV6

ALLOCATION

En IPv6, la notion de rareté n'existe pas : la salle de travaux pratiques, comme
d'autres, est irriguée par un /64 qui ne sera jamais saturé. Dans ce contexte,
il convient de mener une réflexion sur l'adressage à déployer.

Dans un vrai déploiement, nous aurions la main sur les routeurs ascendants et
nous pourrions donc router deux /64 distincts en direction de notre machine qui
héberge notre portail captif.

Dans notre cas, deux pistes apparaissent : utiliser l'allocation d'OSIRIS ou
utiliser une autre allocation.

La première méthode, utiliser l'allocation d'OSIRIS, implique de laisser passer
toute la signalisation ICMPv6 (router solicitation, router advertisement,
neighbor solicitation, neighbor advertisement, principalement). Cela peut être
fait de deux manières :

 * Au niveau 2, en utilisant un bridge. L'inconvénient majeur est que cela nuit
   à la compartimentation que nous souhaitons entre nos différents types d'accès
   (portail captif, accès sécurisé 802.1X) : le trafic multicast (IPv6, IPv4) et
   broadcast (IPv4), y compris celui généré par nos camarades, sera propagé sur
   nos deux réseaux Wi-Fi. Sans compter que cela complexifie probablement la
   configuration initiale de PepperSpot (il faut garantir qu'aucun paquet ne
   traverse le bridge avant que l'utilisateur ait été authentifié. Or, c'est le
   rôle même d'un bridge que de tout laisser passer).
 * En laissant la machine hébergeant notre portail captif en coupure du réseau.
   Mais, comme nous n'avons pas la main sur le routeur qui annonce l'allocation,
   il faut un réseau à plat. Cela implique l'utilisation de la fonctionnalité de
   proxy NDP. D'abord manuelle, cette fonctionnalité peut être automatisée avec
   des logiciels spécialisés tels que ndppd. L'inconvénient majeur de cette
   approche est qu'elle complexifie notre installation au détriment de la
   facilité d'administration sans pour autant offrir des garanties en terme
   d'efficacité.

Dans les deux cas, nous utilisons la même allocation (le même /64) pour nos deux
types d'accès (portail captif et accès sécurisé), ce qui n'est pas optimal d'un
point de vue de la compartimentation.

La deuxième méthode (utiliser une autre allocation que celle d'OSIRIS, pour
rappel) peut être décomposée ainsi :

 * Utiliser une allocation locale unique (fc00::/7) ou réservée pour du
   benchmark et mettre en place du NAPT. Cette technique a fait son apparition
   dans la version 3.7 de Linux (donc elle est disponible dans Debian stable).
   En plus d'être controversée (au motif que ce n'est pas top de reproduire les
   erreurs commises avec IPv4), elle ne permettra pas l'usage de la mobilité
   IPv6, autre point de ce TP, sauf à utiliser des méthodes de contournement
   basées sur UDP (exemple) qui ne sont pas forcément prises en charge par
   toutes les implémentations… ;
 * Utiliser 6in4, soit une encapsulation d'IPv6 sur IPv4. Ça fonctionne tout
   aussi bien en utilisant un VPN (OpenVPN, IPSec, etc.) qui fournit une
   connectivité IPv6, testé et approuvé en 2016. Attention si vous utilisez un
   tunnel de type tun : le nom peut entrer en conflit avec PepperSpot. Avec
   OpenVPN, il est possible de changer le nom de la tun avec la directive de
   configuration suivante : « dev tun ».

Nous avons retenu cette dernière méthode car elle nous semble plus propre, plus
étanche et moins complexe : un tunnel prit chez Hurricane Electric route un /48
sur notre passerelle. De là, un /64 est alloué à chaque réseau (portail captif
et accès sécurisé 802.1X) : 2001:470:c8d6:2::/64 pour TESTAP,
2001:470:c8d6:3::/64 pour TESTAP-sec.

AUTOCONFIGURATION STATELESS OU AUTOCONFIGURATION STATEFUL ?

En IPv6, l'annonce du routeur de sortie du réseau se fait exclusivement via les
messages de contrôle (ICMPv6) « Router Advertisement » (RA). L'attribution des
adresses (et d'autres paramètres comme les serveurs DNS récursifs à utiliser)
peut se faire de deux manières : stateless (SLAAC) ou stateful (DHCPv6).

La difficulté vient de la différence de prise en charge par les différents
systèmes d'exploitation, même les plus récents. En effet, si tous gèrent
l'annonce du routeur de sortie via les messages RA (puisque c'est obligatoire
dans la norme), tous ne prennent pas en charge, en standard, l'annonce des
serveurs DNS récursifs par ce biais (option RDNSS). Avec de tels systèmes, on
n'obtient pas une configuration dual stack : si IPv4 ne fonctionne plus, alors
le serveur DNS récursif est injoignable et IPv6 reste dépendant d'IPv4, ce qui
n'est pas l'objectif de ce TP, à notre avis.

DHCPv6 et les messages RA peuvent cohabiter selon deux modes :

 * Mode « managed » : le message RA sert à indiquer exclusivement l'adresse du
   routeur de sortie. L'attribution des adresses est déléguée à un serveur
   DHCPv6 ;
 * Mode « other configuration » : le message RA sert à indiquer l'adresse du
   routeur de sortie ainsi que le préfixe du réseau afin que les machines
   puissent s'autoconfigurer sans utiliser de serveur DHCPv6. Néanmoins, les
   machines qui supportent DHCPv6 peuvent effectuer une telle requête afin
   d'obtenir des informations d'autoconfiguration complémentaires (comme les
   adresses des serveurs DNS récursifs à utiliser).

Notons que ces modes de fonctionnement diffèrent simplement par des drapeaux à
positionner dans les messages RA.

Sur notre réseau TESTAP-sec, nous utilisons le mode « other configuration »
ainsi qu'un serveur DHCPv6, ce qui permet de prendre en compte un maximum de cas
:

 * Si le système d'exploitation prend en charge RDNSS et DHCPv6, alors il peut
   interroger le serveur DHCPv6 pour consolider les informations complémentaires
   (les adresses des serveurs DNS récursifs, par exemple) obtenues dans le
   message RA (RFC 4862, section 5.6) ;
 * Si le système d'exploitation ne prend pas en charge RDNSS mais prend en
   charge DHCPv6 (exemples : Windows XP-8, Windows Phone 6.5-8, Solaris, etc.),
   il interrogera le serveur DHCPv6 pour connaître les adresses des serveurs DNS
   récursifs (et les autres informations complémentaires) à utiliser ;
 * Si le système d'exploitation ne prend pas en charge DHCPv6 mais prend en
   charge RDNSS (exemples : MeeGo, (Free|Open)BSD, quelques systèmes GNU/Linux
   selon la configuration par défaut, etc.), il récupérera les adresses des
   serveurs DNS récursifs à utiliser directement dans les messages RA ;
 * Si le système d'exploitation ne prend en charge ni RDNSS ni DHCPv6 (exemples
   : Android, Symbian), alors la résolution des noms de domaine est dépendante
   d'IPv4. À l'impossible, nul n'est tenu.

En 2016, je pense qu'il faudrait actualiser cette liste : je serai surpris
qu'Android n'implémente pas au moins RDNSS.

Sur notre réseau TESTAP, nous utilisons uniquement les messages RA : DHCPdv6 ne
peut pas se binder sur l'interface réseau testap car elle n'a pas d'IP
(PepperSport l'attribue à une tun qu'il crée en démarrant) et il ne peut pas non
plus se bind sur une interface point-à-point (la tun créée par PepperSpot),
puisque DHCP est un protocole broadcast/multicast par essence.

IPV4

En IPv4, la question de l'allocation à utiliser ne se pose pas : en raison d'un
manque d'adresses, il n'est pas possible d'attribuer une IPv4 provenant d'OSIRIS
(réseau de l'université) à chacun de nos clients Wi-Fi. On a donc recours à des
adresses privées et à du NAPT.

Dans notre cas, nous avons décidé d'utiliser deux /24 découpés dans le bloc
198.18.0.0/15 réservé à l'IANA pour les tests/benchmarks : 198.18.0.0/24 servira
à adresser notre réseau TESTAP et 198.18.1.0/24 servira à adresser notre réseau
TESTAP-sec.

Notons que nous utilisons 198.18.255.0/31 pour adresser le lien d'administration
de notre point d'accès Wi-Fi.

Les blocs réservés pour un usage privé seraient plus appropriés mais nous
voulions impérativement éviter les collisions avec des adressages existants
(typiquement à nos domiciles respectifs).

GESTION DU RADIUS

Deux consignes informelles ont été ajoutées en cours de route. La première est
que le RADIUS doit récupérer et stocker les informations sur nos utilisateurs
dans une base de données genre MySQL. La deuxième, qui découle de la première,
est que la gestion de cette base doit se faire avec une interface web : il n'est
pas question d'ajouter ou de supprimer un utilisateur ni de consulter
l'accounting avec des bouts de scripts ou manuellement.

Pour ce faire, nous avons choisi le logiciel daloRADIUS. Nous avions aussi
identifié dialupadmin par les auteurs de FreeRADIUS mais son interface web est
un peu rustique à notre goût.

De toute façon, aucun des logiciels libres de gestion des données d'un serveur
RADIUS que nous avons identifiés ne permet nativement de travailler avec les
IPv6 attribuées aux utilisateurs de nos réseaux Wi-Fi. Mais, ce n'est pas
vraiment un problème puisque, pour notre réseau TESTAP-sec, nous verrons que
notre AP Cisco ne communique pas les IP d'un utilisateur dans ses requêtes
d'accounting. Pour notre réseau TESTAP, PepperSpot autorise l'utilisateur à
utiliser uniquement une IPv6 strictement dérivée de son adresse MAC. Dans ce
contexte, l'accounting IPv6 est inutile : la MAC est dans l'adresse IPv6 (avec
un ff:fe en plus en plein milieu, certes). Donc, il suffit d'extraire la MAC à
partir de l'IPv6 et de rechercher l'identifiant à partir de cette adresse-là
(qui est stockée dans l'accounting RADIUS).

Après coup, nous nous sommes rendu compte que le code de dalORADIUS laisse à
désirer : des fonctionnalités présentes sur l'interface web n'ont aucun code
derrière (exemple : le stockage d'un mot de passe utilisateur haché avec SHA1),
le code est doublonné (code identique dans plusieurs pages) ce qui rend
difficile l'ajout d'une fonctionnalité à l'existant, les requêtes de comptage du
nombre de lignes présentes dans la BDD sont insensées, la cohérence du code
(pour une même action, les traitements diffèrent parfois d'une page à une autre)
laisse à désirer, aucune convention de codage, etc.

MÉCANISMES D'AUTHENTIFICATION 802.1X

Pour l'authentification, 802.1X utilise EAP qui est un protocole générique de
transport de méthodes d'authentification (voir
http://www.bortzmeyer.org/3748.html). Parmi toutes les méthodes
d'authentification disponibles, nous avons choisi d'utiliser EAP-TTLS-(PAP|CHAP)
sur notre SSID sécurisé.

TTLS (Tunneled TLS) se justifie car :

 * TTLS est un mécanisme fiable et normalisé à l'IETF ;
 * LEAP est un mécanisme propriétaire de Cisco qui est vulnérable depuis plus de
   10 ans ;
 * PEAP est similaire à TTLS mais les mécanismes d'authentification utilisables
   dans le tunnel sont faibles : MSCHAPv2 et MD5. MD5 n'est plus considéré comme
   sûr depuis plus de 10 ans. Nous allons évoquer MSCHAPv2 ci-dessous ;
 * TLS est trop contraignant car il faut réaliser une authentification du client
   avec un certificat x509 en plus du certificat x509 du serveur, ce qui nuit à
   un usage à grande échelle ;
 * Les autres méthodes sont peu implémentées/utilisées.

Pour réaliser l'authentification à l'intérieur du tunnel TLS au-dessus d'EAP,
plusieurs mécanismes sont possibles :

 * MSCHAP(v2), une implémentation de CHAP réalisée par Microsoft qui est
   totalement trouée de nos jours puisqu'il repose sur l'algorithme
   cryptographique DES et ses clés de 56 bits ;
 * MD5, qui n'est plus considéré comme sûr pour des opérations cryptographiques.
   Certes, on est à l'intérieur d'un tunnel TLS mais son nom est trop connu :
   son utilisation ici pourrait faire croire à nos utilisateurs qu'il est un
   algorithme potable et conduire à des erreurs d'appréciation dans leurs
   projets (pouvoir de prescription) ;
 * CHAP, qui a recours à une fonction de hachage, ce qui rajoute une surcouche
   inutile à un tunnel TLS bien négocié, à notre avis, mais rien n'empêche de
   l'utiliser ;
 * PAP, qui est un mécanisme simple qui envoie l'identifiant et le mot de passe
   en clair dans le tunnel TLS. Pas de protection contre les rejeux comme en
   propose CHAP mais TLS s'occupe aussi de cela.

C'est pourquoi nous avons choisi de tolérer PAP et CHAP comme mécanismes
d'authentification au sein de nos tunnels EAP-TTLS, sur notre réseau TESTAP-sec.

SUPERVISION ET MÉTROLOGIE

Note de 2016 : dans un vrai déploiement, il faudrait plutôt ajouter notre
service Wi-Fi à la supervision existante et ne pas déployer des outils de
supervision/métrologie sur la passerelle du réseau Wi-Fi comme nous allons le
faire. Néanmoins, c'était l'une des consignes du TP et je pense qu'elle a pour
but de nous faire mettre en œuvre une solution de supervision… même si une autre
matière du programme, administration des réseaux (si ma mémoire est bonne),
poursuit le même objectif.

SUPERVISION

Nous utilisons Monit pour superviser les services cruciaux de notre
infrastructure :

 * Point d'accès Cisco : ping et SNMP ;
 * Apache : processus lancé et tentative de requête ;
 * Freeradius : processus lancé et tentative de requête ;
 * MySQL : processus lancé et tentative de requête ;
 * Rsyslogd : processus lancé ;
 * NTPd : processus lancé et tentative de requête ;
 * DHCP(v6) : processus lancé (Monit ne supporte pas ce protocole pour une
   tentative de requête).

Nous avons choisi Monit pour sa simplicité d'où il ne va pas bombarder notre clé
USB bootable d'IO. Il suffit amplement pour atteindre l'objectif fixé par ce TP.
Et j'écris ça avec du recul, après avoir touché à du Zabbix, à du Centreon et à
du Icinga (1.X et 2.X) (tous des usines à gaz) dans mes expériences pros et
associatives depuis ce TP. Un avantage de Monit, c'est qu'il vérifie facilement,
sans trop de configuration, que des processus sont en cours d'exécution. Utile
pour superviser rsyslog sans faire entrer des données prédictibles dans les
logs, par exemple.

Monit est un logiciel de monitoring extrêmement limité, aussi bien en terme de
protocoles supportés qu'en terme de tests effectués : le fait qu'un processus
soit lancé ne signifie pas forcément qu'il va servir la requête d'un utilisateur
; envoyer un paquet générique pour vérifier qu'un port est ouvert est
insuffisant. Illustration (hors cadre de ce TP) : tester qu'un serveur DNS qui
fait autorité répond est insuffisant : il faut comparer les serials de tous les
SOA de tous les serveurs qui font autorité sur une même zone, entre autres
choses. Néanmoins, Monit est suffisant et cohérent dans le cadre de ce projet.
Notons néanmoins que la version de Monit packagée dans Debian Jessie n'est pas
compatible IPv6…

La principale limite de notre infrastructure de supervision est qu'elle teste
les services indépendamment les uns des autres. Mais ce n'est pas parce qu'on
vérifie qu'Apache sert bien la page de notre portail captif que ça signifie
qu'il n'y aura aucun problème lors de la soumission d'un couple identifiant/mot
de passe. Pour être sûr que toute notre infrastructure fonctionne, il faudrait
tester la chaîne de bout en bout : connexion sur chaque SSID, authentification,
envoi de trafic vers une mire choisie en v4 et en v6, etc. À notre connaissance,
aucun logiciel n'existe pour faire un tel test de bout en bout.

MÉTROLOGIE

Nous utilisons Munin pour grapher les composants de la machine qui héberge notre
portail captif : charge CPU, utilisation mémoire, nombre de processus,
entrées/sorties sur les périphériques de stockage, température, etc. Autant de
facteurs qui peuvent révéler des anomalies en cours ou passées (puisque nous
avons un historique). De même, nous graphons le trafic sur les différentes
interfaces réseau, ce qui nous permet de constater, par des données chiffrées,
l'utilisation de nos deux réseaux Wi-Fi.

Nous avons choisi munin pour sa renommée et sa simplicité de configuration et
d'utilisation dans un contexte aussi simple que le nôtre.

TYPOLOGIE DES FLUX RÉSEAUX

Pour moi, en 2016, je pense que nous sommes au-delà de ce que devrait
s'autoriser à faire un FAI mais ce n'est pas illégal pour autant. Ce point est
exigé dans le sujet et il nous a été rappelé lors de la première séance de
notation.

Pour obtenir une visualisation fine des flux réseaux qui passent via notre
hotspot, nous utilisons ntop-ng, version améliorée de ntop : interface web revue
(moins de bugs, plus efficace), plus de données volumétriques récoltées et
affichées, etc. Ça vaut bien un Netflow / IPFix.

Après coup, je trouve curieux que le prof' nous ait indiqué ce logiciel (ou plus
précisément sa première version, ntop) alors qu'il se met en écoute uniquement
en IPv4. 😉


ARCHITECTURE DÉPLOYÉE

Voici un schéma général de l'architecture du réseau que nous avons déployé :

Architecture générale de notre réseau.

Nous utilisons un switch car notre machine passerelle est équipée d'une seule
carte réseau filaire. Notre machine (appelée serveur sur le schéma) regroupe
l'intégralité des services utilisés : PepperSpot, RADIUS, MySQL, Apache,
DHCP(v4/v6), radvd, etc.

VLANS

Dans notre architecture, nous avons deux SSID : TESTAP, qui redirige le client
vers notre portail captif PepperSpot et TESTAP-sec qui utilise une
authentification 802.1X. Chaque SSID est affecté à un VLAN : numéro 2 pour
TESTAP, numéro 3 pour TESTAP-sec. Les communications inter-VLAN, ou depuis un
des réseaux Wi-Fi vers le réseau de management du point d'accès Wi-Fi, sont
interdites.

Le VLAN numéro 1 chez Cisco est le VLAN de management natif (pas tagué) et nous
l'utilisons pour toutes les communications avec le point d'accès : RADIUS pour
802.1X, configuration en ligne de commande (SSH) du point d'accès, etc.

Sur les modèles Aironet de Cisco, il est possible de changer l'ID du VLAN natif
de management, mais il est impossible de taguer ce VLAN. En conséquence, nous
utilisons l'aliasing IP pour configurer notre machine passerelle sur nos
différents réseaux et pour différencier le trafic entrant/sortant depuis/vers
Internet et le trafic circulant sur le VLAN de management.


DONNÉES DE CONNEXION

GÉNÉRALITÉS

La législation française impose aux Fournisseurs d'Accès à Internet (FAI) de
communiquer aux autorités, dans le cadre d'une procédure judiciaire, toutes les
informations associées à une adresse IP dont le FAI aurait connaissance. Cette
obligation court pendant un an.

Dans un contexte de 56k avec une identification "toto/toto", le FAI donne le
numéro de téléphone appelant. Dans un contexte de VPN "open-bar", le FAI
communique l'IP source qui a servie à monter le tunnel. Dans un contexte de
Wi-Fi ouvert, le FAI donne l'adresse MAC (c'est par exemple le cas à l'aéroport
de Toulouse-Blagnac). Il n'y a pas d'obligation de conserver une identité au
sens identité d'état civil.

Si c'est un-e abonné-e et que le FAI a des infos sur lui-elle (identité, adresse
postale, adresse mail, autre), il doit les donner.

S'il s'agit d'un service payant, le FAI doit garder les informations relatives
au paiement.

S'il y a la création d'un compte, il faut communiquer les hashs et la réponse
aux questions secrètes mais pas le mot de passe en clair.

Il est strictement interdit (CPCE) de garder trace de qui a visité tel site. Il
est interdit de conserver tout ce qui touche au contenu ou à la navigation.

Les consignes informelles données lors de ce TP font que l'on sent qu'une
association IP(v4|v6)<->identifiant est attendue. C'est donc dans cette
direction que nous avons creusée même si cela n'est pas nécessaire d'un point de
vue légal si l'on dispose de blocs IP dédiés aux réseaux Wi-Fi, comme nous
venons de le formuler ci-dessus.

AUTHENTIFICATION UAM

PepperSpot garantit l'association identité<->MAC<->IP. L'utilisateur ne peut pas
changer d'IPv4 ni d'IPv6 après son authentification. Par ailleurs, le seul
schéma d'adressage IPv6 pris en charge par PepperSpot est celui dans lequel
l'adresse IPv6 dérive de l'adresse MAC. Il n'est donc pas possible d'utiliser
les adresses IPv6 temporaires des extensions pro-vie privée, par exemple
(PepperSpot est donc incompatible avec un client Wi-Fi Unbuntu sans une
désactivation préalable de ces extensions).

Ici, le portail captif est un NAS dans la terminologie RADIUS. L'accounting
RADIUS de base enregistre les informations suivantes à propos du client :
identifiant, MAC, IPv4, début de la session, fin de la session, octets envoyés
et reçus.

Néanmoins, nous avons complété cet accounting de base :

 * Nous avons positionné la valeur « 120 » pour l'attribut «
   Acct-Interim-Interval ». Cela permet de forcer le portail captif à faire une
   mise à jour de l'accounting toutes les deux minutes, histoire d'avoir des
   informations actualisées sur nos clients Wi-Fi.
 * Nous avons positionné la valeur « 600 » pour l'attribut « Idle-Timeout ».
   Cela permet de déconnecter un utilisateur qui aurait oublié de se déconnecter
   manuellement au bout de 10 minutes d'inactivité (au niveau réseau).
 * Nous aurions pu positionner l'attribut « Session-Timeout » pour donner un
   temps maximal à la connexion à notre hotspot Wi-Fi et pour forcer
   l'utilisateur à se re-identifier comme cela se fait dans les trains et les
   aéroports, mais c'est extrêmement contraignant donc nous ne l'avons pas fait.
 * Nous avons modifié le schéma de la base de données et les requêtes
   d'accounting que freeRADIUS effectue afin d'intégrer le stockage de l'IPv6 de
   notre client Wi-Fi. Nous avons également modifié daloRADIUS (interface web
   pour configurer simplement le RADIUS, pour rappel) afin qu'il récupère et
   affiche ces IPv6.

Pour notre réseau TESTAP, conserver l'accounting RADIUS est suffisant pour
atteindre l'objectif fixé.

AUTHENTIFICATION 802.1X

L'authentification 802.1X garantit uniquement l'association entre une adresse
MAC et un couple identifiant/mot de passe. On est donc en couche 2 uniquement.
Dans cette configuration, nous n'avons plus le contrôle forcené de notre portail
captif : l'utilisateur peut changer d'IP, v4 comme v6, après son
authentification.

De plus, dans cette configuration, le NAS est notre point d'accès Cisco. Or, ce
dernier n'envoie pas les IP obtenues par le client Wi-Fi dans les requêtes
d'accounting (accounting-request) bien que le point d'accès connaisse l'IPv4 du
client et l'affiche dans la sortie de la commande « sh dot11 associations » même
si ce dernier en change après authentification. En revanche, l'adresse IP d'un
client peut-être récupérée via SNMP mais, à l'inverse, l'adresse MAC de ce même
client ne peut pas être récupérée car cela n'est pas prévu dans la MIB. Cela
nous est donc inutile : nous avons besoin de stocker ces deux informations pour
avoir une association entre identifiant et IP.

Nous pouvons conserver les logs DHCP (v4 et v6) mais ils sont insuffisants : un
utilisateur peut fixer ses adresses IP manuellement. De plus, en IPv6,
l'autoconfiguration stateless permet de se passer de DHCPv6, ce qui rend inutile
tout log DHCPv6.

Sur OSIRIS(-sec), la direction informatique (DI) de l'université collecte toutes
les adresses MAC sur tous les commutateurs et toutes les associations MAC<->IP
sur les routeurs. Un outil interne agrège toutes les données (association
identité<->MAC<->IP) et un moteur de recherche, développé aussi en interne,
permet de retrouver la bonne information en cas de réquisition. Il ne leur
semble pas exister de solution plus fiable.

Dans le cadre de ce projet, nous avons mis en place une solution similaire à
celle déployée sur OSIRIS(-sec) mais sans l'énergie dépensée par la DI : nous
enregistrons les associations MAC<->IP avec deux logiciels : arpwatch (IPv4) et
ndpmon (IPv6). Dès qu'un client Wi-Fi émet sur le réseau, pouf, nous avons
l'association entre son adresse MAC et ses IPs. Toute machine qui rejoint le
réseau ou change sa MAC ou reprend une IP allouée à quelqu'un d'autre sera
détectée. En cas de réquisition judiciaire concernant une IP, il suffira de
chercher, dans les logs arpwatch et ndpmon, la MAC associée puis d'aller
chercher les informations (identité, plage horaire de connexion, etc.) relatives
à cette adresse MAC dans l'accounting RADIUS. Le développement d'un moteur de
recherche convivial dépasse le cadre de ce TP.

OUTRO

Nous avons aussi mis en place une conservation des associations MAC<->IP sur le
SSID UAM dans un objectif de sécurité supplémentaire (ceinture et bretelles).
Les logs ainsi produits peuvent être croisés avec l'accounting RADIUS afin
d'être sûrs de la véracité de l'information, par exemple.

Note : pour enregistrer les associations IPv6<->MAC, nous aurions pu avoir
recours à Netfilter pour noter tous les messages ICMPv6 « Neighbor Advertisement
». Il ne semble rien exister de tel pour IPv4 pour l'environnement GNU/Linux
(iptables travaille à partir de la couche 3 donc au-dessus d'ARP et arptables
n'implémente pas de cible « LOG »). De plus, arpwatch et ndpmon permettent de
prévenir les administrateurs de toute tentative (même infructueuse) d'usurpation
d'une adresse MAC, ce que ne permet pas un simple log ip6tables. Pour bénéficier
de cette dernière fonctionnalité, il faudra simplement activer les
fonctionnalités d'envoi de mail en cas d'événements critiques dans ces deux
logiciels. Mais cela dépasse le cadre de ce TP.


PAGE D'ADMINISTRATION

La tâche principale d'administration, à savoir ajouter/supprimer un utilisateur
afin que celui-ci ait accès ou non à notre hotspot, se fait avec daloRADIUS,
interface web qui permet d'interagir avec la base de données utilisée par
freeRADIUS.

La supervision et la métrologie se vérifient à partir des interfaces web des
outils déployés (monit, munin, ntop-ng).

Les autres tâches (mises à jour du système, maintenance, consultation des logs,
etc. ) se réalisent en ligne de commande.

De manière informelle, il nous a été demandé de créer une sorte de page
d'accueil de nos outils d'administration : une page qui afficherait les
informations importantes issues de l'accounting RADIUS concernant les
utilisateurs actuellement connectés à notre hotspot et qui proposerait des liens
pertinents vers les outils d'administration que nous avons déployés (exemple :
un lien sur une IP conduirait à la page ntop-ng concernant cette IP).

Partant de là, nous avons décidé de récupérer des données intéressantes (uptime,
charge CPU, mémoire, nombre de clients Wi-Fi connectés, etc.) depuis notre point
d'accès Cisco en utilisant SNMP et de les afficher sur cette page
d'administration. Histoire de montrer qu'on sait vaguement utiliser SNMP, étudié
précédemment dans une autre matière (administration des réseaux, si ma mémoire
est bonne).

Cette page d'administration est disponible sur https://localhost/admin. (en IPv4
et en IPv6, forcément 😉 ). Identifiant/mdp : toor/toor.


MOBILITÉ IPV6

KÉZAKO ?

L'idée derrière la mobilité IP (ça existe aussi en IPv4), c'est qu'une machine
conserve ses IP lorsqu'elle change de réseau, ce qui lui permet de conserver ses
connexions actives. Utilité ? Les chercheurs voient ça pour les voitures
connectées qui devront se connecter à des réseaux différents tout au long de
leur déplacement. Ou pour nos ordiphones, qui pourraient ainsi passer d'un
réseau Wi-Fi à un réseau 4G sans interruption de service.

Comment cela se matérialise-t-il ? Un entête IPv6 "mobility" chaîné à un entête
IPv6 standard, des options IPv6, de nouveaux messages ICMPv6, etc. En gros, cela
forme un tunnel similaire à un tunnel ip6ip6. Ce tunnel peut être protégé par
IPSec. À mes yeux, c'est donc une énième solution de tunneling. Je pense que le
principal avantage de MIPv6 est sa légèreté dans un usage avec chiffrement
(comparé à un OpenVPN en couche 7 + userland ou à du IPSec + GRE, par exemple).

CHOIX DE L'IMPLÉMENTATION

Nous avons utilisé umip (ex-mipd6) simplement parce que le prof' a dit que
c'était l'implémentation qu'il utilise pour monter le Home Agent avec lequel
notre Mobile Node devra communiquer. Cette partie du sujet ne nous a pas semblé
être assez significative pour justifier une recherche et une comparaison
d'autres implémentations.

QUAND LA MOBILITÉ IP RENCONTRE BCP38

Nous avons constaté qu'il est impossible d'installer un Mobile Node IPv6
derrière une connexion Free ou FDN (et sans doute d'autres fournisseurs d'accès
à Internet). Hurricane Electric (fournisseur de tunnels 6in4) n'est pas
concerné.

Après quelques recherches, nous avons constaté que le « Binding Update »
parvient jusqu'au Home Agent (celui installé par le prof' ou un autre, sur un
réseau sur lequel nous avons la main) mais que le « Binding Ack » n'atteint pas
le Mobile Node.

Cela ne peut pas venir d'un blocage (à cause des options IPv6 utilisées, par
exemple) puisque l'un des fournisseurs d'accès à Internet que nous utilisons,
FDN, fait de la neutralité du réseau son cheval de bataille.

La cause la plus probable semble être l'utilisation, par ces FAI, de l'ingress
filtering (RFC 2827 et 3704 pour les réseaux multihomés, dit BCP38). En effet,
l'ingress filtering posait problème avec la mobilité IPv4 (voir la section 5 du
RFC 2827) et peut encore en poser avec Mobile IPv6 même si le Mobile Node ne met
plus sa home address comme source des paquets qu'il émet (voir, entre autres, ce
brouillon de standard).

En 2016, je suis en mesure de confirmer cette hypothèse. En installant un Home
Agent dans une VM ARN et un Mobile Node chez Grifon, je constate que le message
« Binding Ack » est filtré par le routeur d'entrée de Grifon lorsque le
mécanisme bcp38 est activé.


MISE EN ŒUVRE

CONFIGURER UN POINT D'ACCÈS CISCO AIRONET 1120B

La première étape, c'est de revenir à la configuration par défaut. On zieute les
instructions de Cisco. En résumé : il faut appuyer sur le bouton « MODE » tout
en allumant l'AP, jusqu'à ce que la LED change de couleur.

Après son redémarrage automatique, la borne récupérera une IPv4 via DHCP et on
pourra se connecter à l'interface d'admin en telnet en utilisant le couple
identifiant/mdp Cisco/Cisco.

On configure les paramètres principaux : nom, domaine, ajout d'un utilisateur,
suppression de l'utilisateur Cisco, activer SSH, assigner une IP à l'interface
d'administration, etc. Pour cela, on suit ce tutoriel : Configuration minimale
d'une borne Cisco Aironet 1200 Series.

Ensuite, on vire CDP :

interface fa0
 no cdp enable
 
interface Dot11Radio0
 no cdp enable

Maintenant, créons nos VLAN. D'abord, le VLAN d'administration (natif, pas
tagué) :

interface fa0.1
 description admin
 encapsulation dot1Q 1 native
 bridge-group 1
 no cdp enable
 bridge-group 1 spanning-disabled

Puis on crée les VLANs de nos réseaux Wi-Fi :

interface fa0.2
 description TESTAP
 encapsulation dot1Q 2
 bridge-group 2
 no cdp enable
 bridge-group 2 spanning-disabled
 
interface fa0.3
 description TESTAP-sec
 encapsulation dot1Q 3
 bridge-group 3
 no cdp enable
 bridge-group 3 spanning-disabled

On crée les interfaces Wi-Fi qui correspondent :

interface Dot11Radio0.2
 description TESTAP
 encapsulation dot1Q 2
 bridge-group 2
 no cdp enable
 bridge-group 2 spanning-disabled
 
interface Dot11Radio0.3
 description TESTAP-sec
 encapsulation dot1Q 3
 bridge-group 3
 no cdp enable
 bridge-group 3 spanning-disabled

On crée nos deux SSID :

dot11 ssid TESTAP
 vlan 2
 authentication open
 mbssid guest-mode
 
dot11 ssid TESTAP-sec
 vlan 3
 authentication open
 mbssid guest-mode

On accroche nos SSID aux interfaces radio et on allume l'interface :

interface Dot11Radio 0
 mbssid
 ssid TESTAP
 ssid TESTAP-sec
 no sh

Notre point d'accès est désormais configuré, à l'exception de l'authentification
802.1X, de SNMP et d'autres bricoles que nous ajouterons en cours de route.
Faisons les choses dans l'ordre pour un debug plus facile.

Pour rappel : sur les modèles Aironet de Cisco, il est possible de changer l'ID
du VLAN natif de management, mais il est impossible de taguer ce VLAN.

CONFIGURER UN POINT D'ACCÈS LINKSYS WRT54GL AVEC OPENWRT

Nous n'avions pas d'équipements compatibles avec OpenWRT lors de la réalisation
de ce TP, mais, lors de la publication de ce travail en 2016, j'ai trouvé
intéressant de le reproduire avec un AP fonctionnant avec OpenWRT.

Pour revenir à une config par défaut, je re-flashe le WRT54GL. On est limité à
la version Backfire 10.03.01, déclinaison brcm2.4 d'OpenWRT. Les versions plus
récentes d'OpenWRT ou celles de la déclinaison brcm47 sont inutilisables sur un
WRT54GL (lenteurs, plantages, etc.).

Là aussi, on fait la config' de base via telnet (192.168.1.1, pas
d'identifiant/mdp). On change le mot de passe de root (ce qui active SSH) avec
la commande « passwd » habituelle. On change le nom de la machine (et le fuseau
horaire) dans le fichier « /etc/config/system ».

On veut un AP passif donc on désactive le pare-feu, le serveur DHCP, l'interface
web et d'autres bricoles.

J'ai décidé d'utiliser le port WAN pour faire passer mes VLANs car il s'agit
déjà d'un port physiquement isolé des autres, ce qui ressemble fortement à l'AP
Cisco qui a un unique port.

Créons nos VLANs dans /etc/config/network. D'abord, je supprime toute la config
sauf :

#### VLAN configuration
config switch eth0
    option enable   1
 
config switch_vlan eth0_1
    option device   "eth0"
    option vlan     1
    option ports    "4 5"
 
#### Loopback configuration
config interface loopback
    option ifname   "lo"
    option proto    static
    option ipaddr   127.0.0.1
    option netmask  255.0.0.0

Ensuite, ajoutons l'interface d'administration (VLAN 1 pas tagué) à la fin du
fichier :

### Admin iface configuration
config interface admin
    option ifname  "eth0.1"
    option proto   static     
    option ipaddr  198.18.255.1
    option netmask 255.255.255.254

Dans la section sur la configuration des VLANs, on ajoute les VLANs de nos
réseaux Wi-Fi :

config switch_vlan eth0_2
    option device "eth0"
    option vlan   2
    option ports  "4t 5t"
 
config switch_vlan eth0_3
    option device "eth0"
    option vlan   3
    option ports  "4t 5t"

Correspondance entre les ports physiques et les ports logiques : port physique
Internet = 4, port physique 1 = 3, port physique 2 = 2, port physique 3 = 1,
port physique 4 = 0, CPU (pour dire que le WRT54GL fait partie du VLAN et s'il
doit le taguer ou non) = 5.

Notons que, contrairement à notre Aironet Cisco, il est parfaitement possible
d'isoler la liaison de management avec l'AP dans un VLAN tagué en ajoutant des «
t » dans « ports » de « eth0_1 ». Il faudra créer le VLAN (avec l'ID 1, du coup,
mais ça se change) sur la passerelle. Si nous faisions cela, ça change un peu
les règles de filtrage que nous écrirons plus loin.

On crée les interfaces bridges associées aux VLANs :

# VLAN ifaces configuration
config interface testap  
    option type   bridge  
    option ifname "eth0.2"
    option proto  static
    option ipaddr  192.0.2.1
    option netmask 255.255.255.255
 
config interface tapsec    
    option type   bridge  
    option ifname "eth0.3"
    option proto  static
    option ipaddr  192.0.2.2
    option netmask 255.255.255.255

Attention : il ne faut pas que les deux noms d'interface se ressemblent trop (du
genre « testap - testapsec », début identique) sinon un seul bridge sera créé.

Oui, il faut assigner des IP bidons (ici, il s'agit d'IP qui font partie du bloc
réservé à l'IANA pour écrire de la documentation). Sinon, il faut ajouter une
ligne « option proto none » pour chaque bridge. Mais cela entraîne l'erreur : «
/sbin/Wi-Fi: eval: line 1: syntax error: bad substitution » et cela empêche les
interfaces VLAN filaires d'être configurées et montées automatiquement au boot.
Si l'on tente de ne pas mettre « option proto none », on obtient l'erreur «
Interface not found » et le même comportement de non-configuration au boot.

On crée nos SSID, on les associe à l'interface radio et à nos VLANs et on active
l'interface radio. Le tout dans /etc/config/wireless :

config Wi-Fi-iface
    option device      wl0
    option network     testap
    option mode        ap
    option ssid        "TESTAP"
    option encryption  none
 
config Wi-Fi-iface
    option device      wl0
    option network     tapsec
    option mode        ap
    option ssid        "TESTAP-sec"
    option encryption  none

Évidemment, je supprime le SSID « OpenWrt » créé par défaut.

Pour appliquer les modifications :

/etc/init.d/network restart

Notons que la session telnet va être interrompue à cause du retrait du bout de
config "LAN". Il faudra se brancher sur le port WAN et établir une nouvelle
session telnet.

La rupture de la session telnet peut interrompre prématurément le restart. Il
peut donc être nécessaire de l'exécuter une deuxième fois pour que l'ensemble de
la config' devienne effectif.

Vous pouvez obtenir l'erreur « Command 'set ssid' failed: -1 » qui semble être
une race condition (le SSID est assigné deux fois dont une fois quand
l'interface est allumée d'où le driver sort en erreur) corrigée dans les
nouvelles versions d'OpenWRT.

INSTALLER UN SYSTÈME DEBIAN GNU/LINUX SUR UNE CLÉ USB BOOTABLE

Ce tutoriel reste toujours d'actualité : Installing Debian on a USB stick (from
a running Debian system). Si vous installez un environnement graphique, pensez
également à installer un gestionnaire d'affichage genre gdm3.

CONFIGURATION DE BASE DE LA PASSERELLE

VIRER AVAHI

On n'a pas besoin de cette pourriture sur nos réseaux donc :

sudo systemctl disable avahi-daemon.service avahi-daemon.socket
sudo systemctl mask avahi-daemon.service avahi-daemon.socket

NTP

Il est important de maintenir notre système à l'heure, notamment car c'est
l'heure locale qui servira à horodater les logs et l'accounting RADIUS.

On installe l'implémentation NTP de référence :

sudo apt-get install ntp

Config' à mettre dans /etc/ntp.conf :

disable monitor
 
restrict default ignore
 
restrict ntp-p1.obspm.fr nomodify notrap nopeer noquery
restrict canon.inria.fr nomodify notrap nopeer noquery
 
restrict 127.0.0.1
restrict ::1
 
server ntp-p1.obspm.fr iburst prefer
server canon.inria.fr iburst
 
# Undisciplined Local Clock. This is a fake driver intended for backup
# and when no outside source of synchronized time is available. 
server  127.127.1.0 
fudge   127.127.1.0 stratum 10
restrict 127.127.1.0
 
# Driftfile.
driftfile /var/lib/ntp/ntp.drift

On redémarre NTPd avec cette nouvelle config' :

sudo systemctl restart ntp

IPV6

Soit monter un tunnel 6in4 fournit par Hurricane Electric ou SixXS par exemple,
soit monter un tunnel quelconque (OpenVPN, IPSec) qui fournit une connectivité
IPv6 avec au moins 2 * /64. Je vous laisse faire. 🙂

/ETC/NETWORK/INTERFACES

Voici notre fichier /etc/network/interfaces :

# Internet
auto eth0
iface eth0 inet dhcp
 
 
# IPv6 connectivity
auto he-ipv6
iface he-ipv6 inet6 v4tunnel
  address 2001:470:1f12:273::2/64
  endpoint 216.66.84.42
  local 130.79.92.13
  ttl 255
  gateway 2001:470:1f12:273::1
 
 
# AP management
auto eth0:0
iface eth0:0 inet static
  address 198.18.255.0/31
 
 
# TESTAP 
auto testap
iface testap inet manual
  post-up ip link add link eth0 name $IFACE type vlan id 2 2> /dev/null || true
  post-up ip link set $IFACE up
  post-up ip addr add 198.18.0.1/24 dev $IFACE
  pre-down ip addr del 198.18.0.1/24 dev $IFACE
 
iface testap inet6 static
  address 2001:470:c8d6:2::1/64
 
 
# TESTAP-sec
auto tapsec
iface tapsec inet manual
  post-up ip link add link eth0 name $IFACE type vlan id 3 2> /dev/null || true
  post-up ip link set $IFACE up
  post-up ip addr add 198.18.1.1/24 dev $IFACE
  pre-down ip addr del 198.18.1.1/24 dev $IFACE
 
iface tapsec inet6 static
  address 2001:470:c8d6:3::1/64

On applique la nouvelle config' :

sudo systemctl restart networking

ACTIVER L'IP FORWARD

Dans /etc/sysctl.conf, décommenter :

net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

On applique :

sudo sysctl -p

RADVD

On installe :

sudo apt-get install radvd

On configure en mettant ce qui suit dans /etc/radvd.conf :

# TESTAP
interface testap
{
    AdvSendAdvert on;
    MaxRtrAdvInterval 10;
 
    # "You can use DHCPv6 to obtain moar informations"
    # AdvManagedFlag on;
    AdvOtherConfigFlag on;
 
    prefix 2001:470:c8d6:2::/64
    {
    };
 
    RDNSS 2a00:5881:8100:1000::3
    {
    };
 
    RDNSS 2a00:5884:8218::1
    {
    };
};
 
# TESTAP-sec
interface tapsec
{
    AdvSendAdvert on;
    MaxRtrAdvInterval 10;
 
    # "You can use DHCPv6 to obtain moar informations"
    # AdvManagedFlag on;
    AdvOtherConfigFlag on;
 
    prefix 2001:470:c8d6:3::/64
    {
    };
 
    RDNSS 2a00:5881:8100:1000::3
    {
    };
 
    RDNSS 2a00:5884:8218::1
    {
    };
};

On abuse un peu sur le MaxRtrAdvInterval (par défaut, il est configuré à 600
secondes, soit 10 minute) tout en restant au-dessous du minimum indiqué dans le
manuel de radvd (4 secondes). L'idée première est de parer les pare-feu qui
bloquent l'ICMPv6 en sortie donc les « Router Solicitation » sans pour autant
bloquer les « Router Advertisement ». Cela permet aussi de garantir que nos
clients Wi-Fi auront rapidement une IPv6 afin de montrer au prof' que PepperSpot
redirige bien l'utilisateur pour authentification, même en IPv6. Sur un vrai
déploiement en dual stack, il faudrait augmenter cette valeur.

On fait prend en compte la nouvelle configuration :

sudo systemctl restart radvd

DHCP

DHCPV4

On installe l'implémentation de référence :

sudo apt-get install isc-dhcp-server

On écrit la configuration dans /etc/dhcp/dhcpd.conf :

# Seems great for a Wi-Fi network
default-lease-time 1800; # 30 mns
max-lease-time 25200;    # 7  H
 
authoritative;
 
log-facility local7;
 
# TESTAP
subnet 198.18.0.0 netmask 255.255.255.0 
{
    range 198.18.0.10 198.18.0.254;
 
    option subnet-mask 255.255.255.0;
    option broadcast-address 198.18.0.255;
 
    option routers 198.18.0.1;
 
    option domain-name-servers 89.234.141.66, 89.234.186.18; 
}
 
# TESTAP-sec
subnet 198.18.1.0 netmask 255.255.255.0 
{
    range 198.18.1.10 198.18.1.254;
 
    option subnet-mask 255.255.255.0;
    option broadcast-address 198.18.1.255;
 
    option routers 198.18.1.1;
 
    option domain-name-servers 89.234.141.66, 89.234.186.18;
}

On fait prendre en compte la nouvelle config' :

sudo systemctl restart isc-dhcp-server

DHCPV6

Dans l'implémentation DHCP de l'ISC, un même binaire assure le job pour IPv4 et
pour IPv6 : un commutateur permet d'indiquer la version désirée. Aucun
initscript n'est livré dans le paquet Debian pour démarrer un serveur DHCPv6.
Voici notre initscript, librement adapté de l'initscript v4, qui contrairement à
son homologue, n'inclu pas un fichier /etc/default/isc-dhcp6-server (aka tout
est défini dans notre initscript) :

#!/bin/sh
#
# $Id: isc dhcp server.init.d,v 4.2.1-P1 2011/04/05 /usr/local/sbin/dhcpd$
#
 
### BEGIN INIT INFO
# Provides:          dhcpd6-server
# Required-Start:    $remote_fs $network $syslog
# Required-Stop:     $remote_fs $network $syslog
# Should-Start:      $local_fs slapd
# Should-Stop:       $local_fs slapd
# Default-Start:     2 3 4 5
# Default-Stop:      1
# Short-Description: DHCP server
# Description:       Dynamic Host Configuration Protocol Server
### END INIT INFO
 
PATH=/sbin:/bin:/usr/sbin:/usr/bin
 
# config file
NAME=dhcpdv6
DESC="DHCP IPv6 server"
INTERFACES=""
 
SERVER=/usr/sbin/dhcpd
SERVERARGS="-6"
CONFIGFILE=/etc/dhcp/dhcpd6.conf
LIBFOLDER=/var/lib/dhcpv6
LEASEFILE="${LIBFOLDER}/dhcpdv6.leases"
RUNFOLDER=/var/run/dhcpv6
DHCPDPID="${RUNFOLDER}/dhcpdv6.pid"
 
 
# check filetypes/values
test -f "${SERVER}" || exit 0
 
# include all init functions
. /lib/lsb/init-functions
 
test_config()
{
	# 1.) check config
	if [ ! "${SERVER}" "${SERVERARGS}" -t -q -cf "${CONFIGFILE}" > /dev/null 2>&1 ]; then
		echo "${NAME} self-test failed. Please fix the config file."
		echo "The error was: "
		"${SERVER}" "${SERVERARGS}" -t -cf "${CONFIGFILE}"
		exit 1
	fi
 
	# 2.) test_config will started if someone wants to start the server
	# test if the server is currently running
	if [ "${1}" = "start" ]; then
		if [ -e "${DHCPDPID}" ]; then
		  stop_server "Currently running instance of ${DESC} found (PID: `cat ${DHCPDPID}`) - will now stop this instance"
		fi
	fi
}
 
stop_server(){
	if [ "${1}" != "" ]; then
	 log_daemon_msg "${1}"
	fi
 
	if [ -e "${DHCPDPID}" ]; then
	  log_daemon_msg "Stopping ${DESC} ${NAME} [`cat ${DHCPDPID}`]"
	  start-stop-daemon --stop --quiet --pidfile "${DHCPDPID}"
	  log_end_msg $?
	  rm -f "${DHCPDPID}"
	else
	  log_daemon_msg "Stopping ${DESC} ${NAME}: nothing do do, no pidfile found"	
	fi
}
 
# single arg is -v for messages, -q for none
check_status(){
  if [ ! -r "$DHCPDPID" ]; then
    test "$1" != -v || echo "$NAME is not running."
    return 3
  fi
 
  if read pid < "$DHCPDPID" && ps -p "$pid" > /dev/null 2>&1; then
    test "$1" != -v || echo "$NAME is running."
    return 0
  else
    test "$1" != -v || echo "$NAME is not running but $DHCPDPID exists."
    return 1
  fi
}
 
case "$1" in
	start)
	  test_config ${1}
		log_daemon_msg "Starting ${DESC} ${NAME}"
 
		# allow dhcp server to write lease and pid file
		if [ ! -e "${RUNFOLDER}" ]; then
		  # create run folder
		  mkdir -p "${RUNFOLDER}"
		  #chown dhcpd:dhcpd "${RUNFOLDER}"
 
		  # create pid file
		  touch "${DHCPDPID}"
		  #chown dhcpd:dhcpd "${DHCPDPID}"
		else
		   # create pid file
		  touch "${DHCPDPID}"
		  #chown dhcpd:dhcpd "${DHCPDPID}"
		fi
 
		if [ ! -e "${LIBFOLDER}" ]; then
		  # create run folder
		  mkdir -p "${LIBFOLDER}"
		  #chown dhcpd:dhcpd "${LIBFOLDER}"
 
		  # create lease file
		  touch "${LEASEFILE}"
		  #chown dhcpd:dhcpd "${LEASEFILE}"
		else
		   # create pid file
		  touch "${LEASEFILE}"
		  #chown dhcpd:dhcpd "${LEASEFILE}"
		fi
 
		start-stop-daemon --start --quiet --pidfile "${DHCPDPID}" \
			--exec "${SERVER}" -- "${SERVERARGS}" -q $OPTIONS -cf "${CONFIGFILE}"  -lf "${LEASEFILE}" -pf "$DHCPDPID" ${INTERFACES}
		sleep 2
 
 
		if check_status -q; then
		  log_end_msg 0
		else
			log_failure_msg "check syslog for diagnostics."
			log_end_msg 1
			exit 1
		fi
		;;
	stop)
		# stop dhcp server
		stop_server
		;;
 
	restart | force-reload)
		test_config
		$0 stop
		sleep 2
		$0 start
		if [ "$?" != "0" ]; then
			exit 1
		fi
		;;
	status)
		echo -n "Status of $DESC: "
		check_status -v
		exit "$?"
		;;
	*)
		echo "Usage: $0 {start|stop|restart|force-reload|status}"
		exit 1 
esac
 
exit 0

Bon, en 2016, je pense qu'une unit systemd serait plus pertinente et prendrait
moins de temps à être déployée, mais je vous livre quand même cet initscript :
puisqu'il existe, autant qu'il serve.

On active ce service :

sudo chmod +x /etc/init.d/isc-dhcp6-server
sudo systemctl daemon-reload
sudo systemctl enable isc-dhcp6-server

On pose la configuration dans le fichier /etc/dhcp/dhcpd6.conf :

# Enable RFC 5007 support (same than for DHCPv4)
allow leasequery;
 
# TESTAP
subnet6 2001:470:c8d6:2::/64
{
    option dhcp6.name-servers 2a00:5881:8100:1000::3, 2a00:5884:8218::1;
    option dhcp6.info-refresh-time 25200; # 7H
 
    # range6 2001:470:c8d6:2::/64;
}
 
# TESTAP-sec
subnet6 2001:470:c8d6:3::/64 
{
    option dhcp6.name-servers 2a00:5881:8100:1000::3, 2a00:5884:8218::1;
    option dhcp6.info-refresh-time 25200;
 
    # range6 2001:470:c8d6:3::/64;
}

La configuration est répétitive, mais il nous faut obligatoirement de la config'
dans les sections « subnet6 » sinon le serveur refuse de démarrer. Cette
configuration sera simplifiée par la suite.

Si l'on active les options « range6 », notre serveur DHCPv6 répondra aux
requêtes DHCPv6 d'attribution d'adresse. On serait alors dans une configuration
stateful. Comme nous l'avons déjà écrit, ce n'est pas ce que nous voulons.

On démarre le serveur DHCPv6 :

sudo systemctl start isc-dhcp6-server

NAPT

On ajoute une règle de NAPT :

sudo iptables -t nat -A POSTROUTING -o eth0 -j ACCEPT

Nous mettrons en place la persistance de cette configuration lorsque nous
installerons PepperSpot.

TESTER

On peut procéder à un premier test de notre installation en nous connectant à
chacun de nos deux réseaux Wi-Fi. Pour chaque, on doit obtenir une IPv4 dans le
bon réseau, une IPv6 dans le bon réseau, les adresses (v4 et v6) du routeur et
les adresses (IPv4 et IPv6) de nos résolveurs DNS. On doit être en mesure
d'utiliser pleinement Internet.

De plus, à la réception d'un message « Router Advertisement », notre machine
doit émettre une requête DHCPv6 « Information-request » et notre serveur DHCPv6
doit répondre avec un message « Reply » contenant les adresses IPv6 de nos
résolveurs DNS.

Si tout cela est OK, nous pouvons passer à la suite.

AUTHENTIFICATION 802.1X

(FREE)RADIUS

À propos de RADIUS, de FreeRADIUS, d'EAP, etc., je recommande les deux
ressources suivantes : présentation de RADIUS, EAP et FreeRADIUS et formation
vidéo RADIUS.

On installe l'implémentation RADIUS de référence, FreeRADIUS :

sudo apt-get install freeradius

Par défaut, FreeRADIUS écoute uniquement en IPv4. Il faut corriger cela en
ajoutant ce qui suit dans /etc/freeradius/radiusd.conf :

# Listen v6
# For authentication 
listen {
    type = auth
    ipv6addr = ::1
    port = 1812
}
 
# For accounting                                                
listen {
    type = acct
    ipv6addr = ::1
    port = 1813
}

Oui, on pourrait mettre « ipv6addr = * » mais, notre AP Cisco n'étant pas
compatible IPv6, il n'y a que notre portail captif, installé sur la même
machine, qui viendra faire des requêtes.

Dans /etc/freeradius/clients.conf, il faut ajouter les NAS qui seront autorisés
à faire des requêtes auprès de notre serveur :

# localhostv6
client ::1 {
    ipv6addr        = ::1
    secret          = <secret_radius>
    shortname       = localhostv6
}
 
client ap {
    ipaddr          = 198.18.255.1
    secret          = <secret_radius>
}

Notons que quand le nom d'un client peut être résolu, il n'y a pas besoin de
préciser « ipaddr ».

Il faut maintenant ajouter les utilisateurs autorisés à se connecter à notre
base de données. Par défaut, FreeRADIUS utilise uniquement un fichier,
/etc/freeradius/users. Exemple de ligne à ajouter :

guigui    Cleartext-Password := "toor"

Mais stocker les mots de passe en clair, ça tue des chatons. FreeRADIUS prend en
charge quelques fonctions cryptographiques désuètes : NT, MD5, SHA-1, SHA-1 avec
un sel et crypt (oui, la fonction anciennement utilisée pour stocker les mdps de
session dans /etc/shadow, désormais on l'utilise avec un sel et des fonctions de
hachage genre SHA2). On remarquera que tous ces algos sont morts : NT = MD4 =
mort, MD5 = mort, crypt (version originale) = mort, SHA-1 et SHA-1 salé
résistent encore au bruteforce quand elles sont utilisées avec de vrais mots de
passe complexes donc c'est quasiment une illusion sur un hotspot (nous n'aurons
pas de mdp complexes). La seule alternative viable serait de modifier les
modules de FreeRADIUS ou d'utiliser pam plus des algos cryptos encore viable
derrière…

Regardons malgré tout pour SHA1. Pour obtenir le hash d'un mdp de passe, on
utilise la commande suivante :

echo -n "<mdp>" | sha1sum

Exemple de ligne à ajouter dans le fichier users de freeRADIUS :

guigui    SHA1-Password := "<hash>"

On redémarre notre serveur RADIUS avec la nouvelle configuration :

sudo systemctl restart freeradius

On teste notre RADIUS :

radtest -6 <identifiant> <mdp> ::1 0 <secret_radius_pour_localhost>

On doit forcément obtenir un « Accept-Accept » avant de passer à la suite.

802.1X SUR UN AP CISCO AIRONET

Les lignes de commande KiVontBien pour activer l'authentification 802.1X sur
notre SSID TESTAP-sec :

radius-server host 198.18.255.0 auth-port 1812 acct-port 1813 key 0 <secret_radius>
 
aaa group server radius rad_eap
 server 198.18.255.0 auth-port 1812 acct-port 1813
 
aaa authentication identifiant eap_methods group rad_eap
 
int Dot11Radio 0
 encryption vlan 3 mode ciphers tkip 
 
dot11 ssid TESTAP-sec
  authentication open eap eap_methods 
  authentication network-eap eap_methods 
  authentication key-management wpa

802.1X SUR UN AP WRT54GL AVEC OPENWRT

Documentation : Introduction to 802.1x sur le wiki OpenWRT.

Dans /etc/config/wireless, ajouter ce qui suit à notre SSID TESTAP-sec :

    option encryption  wpa2
    option server      198.18.255.0
    option key         <secret_radius>

Puis :

/etc/init.d/network restart

Note : dans la déclinaison brcm2.4 d'OpenWRT, le NAS est un soft privateur de
Broadcom, nommé « nas » (imagination, quand tu nous tiens). Il va de pair avec
le driver Wi-Fi privateur de Broadcom, wl. hostapd prend en charge uniquement le
driver libre mac80211 qui ne prend pas en charge le chip Wi-FI du WRT54GL.
hostapd fonctionne avec le driver libre b43 (qui est présent dans la déclinaison
brcm47 d'OpenWRT) mais ce driver ne permet pas d'émettre plusieurs SSID en même
temps.

TESTER

À partir d'ici, il doit être possible de se connecter à notre réseau TESTAP-sec
en utilisant l'authentification 802.1X. \o/

Pour vous connecter, votre gestionnaire réseau (GNOME Network Manager, par
exemple) vous demandera le certificat x509 public de l'autorité de certification
(AC) qui a signé le certificat de votre AP afin de valider ce dernier. Par
défaut, sous Debian, freeRADIUS utilise un certificat bidon autosigné généré
automatiquement lors de l'installation. Il se trouve dans
/etc/freeradius/certs/server.pem et c'est lui qu'il faudra utiliser. Hé, oui, en
EAP-TTLS, chaque client discute avec le RADIUS : les messages EAP sont
encapsulés dans des messages RADIUS par le NAS qui fait partie intégrante du
point d'accès Wi-Fi. Dans le sens inverse, le NAS relaie aussi les challenges
cryptographiques envoyés par le serveur RADIUS au client afin que ce dernier les
résolve afin de prouver son identité.

Attention avec OpenWRT : le NAS de Broadcom est très chatouilleux : un
acces-reject et votre machine cliente est bloquée (probablement en utilisant la
MAC). J'ai attendu plusieurs heures, pas de déblocage, seul un «
/etc/init.d/network restart » permet de redonner une chance à la machine
cliente. En revanche, on peut se déconnecter/reconnecter du réseau autant de
fois que l'on veut si le RADIUS retourne un « access-accept ». Comportement
incompréhensible. :-

STOCKER LES UTILISATEURS DE NOTRE HOTSPOT DANS MYSQL

On installe le nécessaire :

sudo apt-get install freeradius-mysql mysql-server

On crée la base de données pour freeRADIUS, on crée un utilisateur radius dédié,
on crée un premier utilisateur de notre hotspot :

sudo mysql -u root -p
mysql> CREATE DATABASE radius;
mysql> GRANT ALL PRIVILEGES ON radius.* TO radius@localhost IDENTIFIED BY "<mdp>";
mysql> flush privileges;
mysql> source /etc/freeradius/sql/mysql/schema.sql
mysql> insert into radcheck VALUES (1, 'guigui', 'SHA1-Password', ':=', '<hash_mdp>');
mysql> exit

On utilise « sudo » afin que MySQL puisse lire le fichier
/etc/freeradius/sql/mysql/schema.sql . 😉 On ne restreint pas cet utilisateur en
lecture seule car daloRADIUS utilisera ce compte pour écrire dans la base de
données RADIUS.

Il faut activer le module SQL dans freeRADIUS : dans
/etc/freeradius/radiusd.conf, « $INCLUDE sql.conf » ne doit plus être en
commentaire. Dans /etc/freeradius/sql.conf, il faut changer le mot de passe
permettant de se connecter à la base de données.

Il faut indiquer à freeRADIUS d'utiliser le module SQL pour réaliser
l'autorisation, c'est-à-dire remonter les informations que l'on a sur un
utilisateur depuis la BDD. Pour cela, il faut décommenter « sql » dans la
section « authorize » de /etc/freeradius/sites-enabled/inner-tunnel pour
l'authentification 802.1X (car notre serveur RADIUS connaît le mot de passe de
l'utilisateur uniquement quand le tunnel EAP-TTLS a été établi) et dans la
section « authorize » du fichier /etc/freeradius/sites-enabled/default pour le
portail captif puisque celui-ci n'utilise pas de tunnel.

On met en commentaire notre tout premier utilisateur de test dans
/etc/freeradius/users.

On teste qu'il est toujours possible de nous authentifier sur notre SSID
TESTAP-sec.

ALLÉGER ET SÉCURISER FREERADIUS

Si l'on est sûr que notre RADIUS ne servira pas à faire autre chose que de
l'authentification au-dessus d'EAP, alors on peut mettre en commentaire chap,
mschap, digest et pap dans la section « authorize » de
/etc/freeradius/sites-enabled/default. Le seul module dont nous ayons besoin ici
est eap. Pour le portail captif, le module « sql » ou le module « files »
positionnera un attribut « Auth-Type := PAP » qui activera le bon module dans la
section « authenticate ». On peut également mettre en commentaire « preprocess »
et « suffix », nous n'en avons pas besoin ici (nous n'utilisons pas de huntgroup
ni de realm).

On peut également alléger la configuration du module eap dans
/etc/freeradius/eap.conf. On peut mettre en commentaire md5 (aka eap-md5), leap
(aka eap-leap), peap et mschapv2 dans la section « authorize ». On peut
également changer la valeur de « default_eap_type » pour la passer de « md5 » à
« ttls ». Notons qu'il n'est pas possible de changer la valeur du même «
default_eap_type » dans le module ttls.

On peut également alléger la configuration qui s'applique à tout tunnel EAP
établi. C'est dans /etc/freeradius/sites-enabled/inner-tunnel que cela se passe.
On peut mettre en commentaire mschap, eap et suffix. On notera là aussi que les
modules files et sql autorisent obligatoirement et forcément l'usage de CHAP (et
PAP) pour l'authentification à l'intérieur du tunnel. On ne peut pas désactiver
ce comportement, même en mettant en commentaire toute référence à CHAP/MSCHAP
dans tous les fichiers de freeRADIUS.

Puisque nous utilisons TTLS, donc un tunnel TLS, toutes les recommandations
applicables à TLS s'appliquent ici aussi :

 * Il faut utiliser autre chose qu'un certificat x509 qui n'est pas à votre nom.
   De plus, utiliser autre chose qu'un certificat auto-signé permet d'en changer
   régulièrement sans devoir le diffuser à tous les utilisateurs de votre réseau
   sans fil (diffuser le certificat de l'autorité de certification (AC) suffit).
   Quant à savoir s'il faut utiliser une AC publique reconnue ou une AC privée
   interne à votre organisation pour signer le certificat de votre serveur
   RADIUS, la problématique qui se pose est la même qu'avec OpenVPN : utiliser
   une AC publique vous expose à un point d'accès malveillant portant le même
   nom (les machines de vos clients Wi-Fi s'y connecteront donc automatiquement,
   sans rien demander à leur utilisateur car le standard Wi-Fi est ainsi fait)
   et qui utilisera un certificat x509 parfaitement légitime obtenu auprès de la
   même AC publique que vous pour voler les mots de passe, savoir qui est
   connecté au réseau, etc.
 * Il faudrait normalement utiliser TLS v1.2 ainsi que des suites
   cryptographiques pas complètement moisies, comme dans tout usage de TLS. Sauf
   que la compatibilité avec les clients est loin d'être garantie. Illustration
   : GNOME Network Manager dans Debian Jessie, qui se repose sur wpa_supplicant,
   utilise uniquement TLS v1.0… Pour changer les suites cryptographiques
   autorisées, il faut modifier la valeur de « cipher_list » dans
   /etc/freeradius/eap.conf et ça mange une chaîne habituelle dans le monde TLS.

Pro-tips : j'imagine que vous allez vouloir tester cette nouvelle configuration.
GNOME network-manager est parfois long à la détente quand on change le mode
d'authentification. Ce qui fait qu'on a choisi « MD5 » (alors qu'on utilisait
PAP avant, par exemple) et que l'on constate que l'authentification fonctionne.
Ce n'est pas que freeRADIUS a accepté du EAP-MD5 (qu'on vient de désactiver)
mais simplement que GNOME Network Manager a bien utilisé du EAP-PAP. Il faut
réessayer et là, l'authentification échouera. Mon conseil est de lancer
freeradius en mode debug avec la commande « freeradius -X ». Comme cela, on voit
très précisément les modules qui ont été utilisés et les résultats produits.

PEPPERSPOT

FAIRE LE MÉNAGE

PepperSpot s'occupe de l'adressage de son interface réseau de travail et de
fournir un serveur DHCPv4. Il faut donc mettre en commentaire notre
configuration applicable à TESTAP dans /etc/dhcp/dhcpd.conf et redémarrer le
serveur DHCPv4. Même chose pour DHCPv6 qui ne pourra pas se binder sur
l'interface tun crée par PepperSpot comme nous l'avons déjà exposé. De même, le
fichier /etc/network/interfaces doit désormais ressembler à ça pour notre
interface testap (le reste est inchangé) :

# TESTAP 
auto testap
iface testap inet manual
  post-up ip link add link eth0 name $IFACE type vlan id 2 2> /dev/null || true
  post-up ip link set $IFACE up
 
iface testap inet6 manual

LIRE LE MANUEL

Le fichier README de PepperSpot est plutôt complet. Après toute la configuration
qu'on a déjà abattu, les sections encore pertinentes sont la 3 sur la
configuration du serveur web pour servir la page d'auth, la 1,3 et 1,4 sur les
dépendances nécessaires à la compilation de PepperSpot, la 5 sur la compilation,
l'installation et la configuration ainsi que la 6 sur le lancement du portail
captif.

Je vais formuler quelques remarques complémentaires ci-dessous.

REMARQUE SUR L'IPV6 FORWARDING ET L'AUTOCONFIGURATION IPV6 (SECTION 1.1.3)

Avec Linux, il est parfaitement possible d'être un routeur et d'accepter des
messages RA sur certaines interfaces pour s'autoconfigurer. Pour ce faire, il
faut donner la valeur « 2 » à « net.ipv6.conf.all.forwarding » dans sysctl.conf.
Pas besoin de Quagga ni du protocole de routage RIP.

REMARQUES SUR LE SERVEUR WEB

La version PHP du portail captif fonctionne très bien out-of-box dès lors que
l'on a installé libapache2-mod-php5, ce qui est logique.

Pour la version CGI, il faut activer CGI :

sudo a2enmod cgi && sudo systemctl reload apache2

Notons que le script n'est pas prévu pour être exécuté par fcgid car il provoque
l'affichage du portail captif dans les logs d'Apache et, car la variable
d'environnement « HTTPS » (qui indique si l'URL demandée contient « https »)
n'est pas définie par fcgid, ce qui ne convient pas à PepperSpot.

Dans tous les cas, depuis Apache 2.4, il convient de remplacer les lignes «
Order [...] » par « Require all granted ». De même, le fichier représentant le
virtualhost doit avoir une extension « .conf » afin qu'il soit pris en
considération par Apache.

REMARQUES SUR LES RÈGLES DE FILTRAGE

Dans pepper.iptables, en plus d'effectuer la modification des variables $EXTIF4
et $INTIF4, nous modifions la règle « $IPTABLES -A INPUT -i $EXTIF4 -j REJECT »
pour remplacer le REJECT par un DROP. Ensuite, nous autorisons notre AP Cisco à
causer avec notre serveur RADIUS (à mettre avant la règle précédemment modifiée)
:

$IPTABLES -A INPUT -i $EXTIF -s 198.18.255.1 -d 198.18.255.0 -p udp -m multiport --dports 1812,1813 -m state --state NEW -j ACCEPT

Nous décommentons également la règle « Allow ICMP echo on other interfaces
(input) », car c'est toujours utile pour debug.

Enfin, avant « Drop everything to and from $INTIF (forward) », on ajoute les
règles suivantes pour empêcher tout trafic entre nos clients Wi-Fi et le réseau
de management :

$IPTABLES -A FORWARD -i testap -d 198.18.255.0/31 -j DROP
$IPTABLES -A FORWARD -i tun0 -d 198.18.255.0/31 -j DROP
$IPTABLES -A FORWARD -i tapsec -d 198.18.255.0/31 -j DROP

Et l'on ajoute les règles suivantes pour éviter tout trafic entre nos deux
réseaux Wi-Fi :

$IPTABLES -A FORWARD -i testap -o tapsec -j DROP
$IPTABLES -A FORWARD -i tun0 -o tapsec -j DROP
 
$IPTABLES -A FORWARD -i tapsec -o testap -j DROP
$IPTABLES -A FORWARD -i tapsec -o tun0 -j DROP

Pour faire propre, on peut créer des variables au début du script pour stocker
tapsec, tun0 & co mais on va voir que le but de ce script est de servir de rares
fois. 🙂

Dans pepper.ip6tables, en plus d'effectuer la modification des variables $EXTIF4
et $INTIF4, nous mettons en commentaire la règle qui autorise RIPng. Nous
modifions également la règle « $IP6TABLES -A INPUT -i $EXTIF6 -j REJECT » pour
remplacer le REJECT par un DROP.

Nous ajoutons une règle pour autoriser DHCPv6 depuis l'intérieur et ping6 depuis
partout (avant « Allow everything on loopback ») :

$IP6TABLES -A INPUT -i tapsec -p udp --sport 546 --dport 547 -j ACCEPT
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT

Avant « Drop everything to and from $INTIF (forward) », nous ajoutons les règles
suivantes pour bloquer tout trafic entre nos deux réseaux Wi-Fi :

$IP6TABLES -t filter -A FORWARD -i testap -o tapsec -j DROP
$IP6TABLES -t filter -A FORWARD -i tun1 -o tapsec -j DROP
 
$IP6TABLES -t filter -A FORWARD -i tapsec -o testap -j DROP
$IP6TABLES -t filter -A FORWARD -i tapsec -o tun1 -j DROP

Note : fermer le port 3990 est une mauvaise idée : PepperSpot utilise ce port
pour communiquer avec lui-même pour l'authentification.

Pour rendre ces règles de filtrage persistantes, nous utilisons
netfilter-persistent. D'abord, on ajoute les règles à Netfilter en exécutant les
scripts pepper.iptables et pepper.ip6tables. Ensuite, on installe
netfilter-persistent :

sudo apt-get install netfilter-persistent iptables-persistent

Lors de l'installation, il sera demandé s'il faut conserver les règles de
filtrage existantes. Il faudra acquiser. Les règles de filtrage (et de NAPT)
seront restaurées à chaque boot de la passerelle.

REMARQUE SUR LA CONFIGURATION

Voici notre fichier /etc/pepper.conf une fois les lignes vides ou commentées
retirées :

ipversion dual
net 198.18.0.0/24
staticipv6 2001:470:c8d6:2::1
ipv6prefix 2001:470:c8d6:2::/64
dns1 89.234.141.66
dns2 89.234.186.18
radiusserver1 ::1
radiusserver2 127.0.0.1
radiussecret <secret_radius>
radiuslocationid isocc=fr,cc=33,ac=67000,network=portail_ipv6
dhcpif testap
uamserver https://198.18.0.1/cgi-bin/hotspotidentifiant.cgi
uamserver6 https://[2001:470:c8d6:2::1]/cgi-bin/hotspotidentifiant.cgi
uamsecret testing234

REMARQUES SUR LE LANCEMENT AUTOMATIQUE

Dans un premier temps, on peut lancer PepperSpot en premier plan pour voir si la
config' est OK :

sudo pepper -fd

Un bout d'initscript est présent dans le dossier « debian » des sources, mais
une unit systemd nous a paru plus adaptée (nous la stockons dans
/etc/systemd/system/pepperspot.service) :

[Unit]
Description=Pepperspot
After=syslog.target network.target netfilter-persistent.service
 
[Service]
Type=simple
ExecStart=/usr/sbin/pepper
 
[Install]
WantedBy=multi-user.target

On active ce service et on le lance :

sudo systemctl enable pepperspot
sudo systemctl start pepperspot

DONNÉES DE CONNEXION

ACCOUNTING RADIUS

SUR UN POINT D'ACCÈS CISCO AIRONET 1120B

Pour activer l'accounting RADIUS, il faut utiliser les commandes suivantes :

aaa accounting network acct_methods start-stop group rad_eap
 
dot11 ssid TESTAP-sec
 accounting acct_methods

Pour rappel : l'AP n'envoie pas les adresses IP du client dans les requêtes
d'accounting. L'attribut RADIUS correspondant, « Framed-IP-Address » peut
seulement être ajouté aux requêtes de demande d'accès en utilisant la commande «
radius-server attribute 8 include-in-access-req ».

SUR UN POINT D'ACCÈS WRT54GL AVEC OPENWRT

Le NAS privateur de Broadcom ne prend pas en charge l'accounting RADIUS. hostapd
le fait, mais nous avons vu qu'il n'est pas utilisable avec notre WRT54GL.

ACTUALISATION FRÉQUENTE…

Un NAS peut remonter fréquemment au serveur RADIUS les données concernant un
client (volume de données échangé, etc.). Par défaut, notre AP Cisco Aironet
envoie uniquement des Accounting-Start et des Accounting-Stop qui marquent le
début et la fin de la connexion du client Wi-Fi. Par défaut, PepperSpot envoie
des informations toutes les 10 minutes. Lorsqu'on est sur de la facturation au
volume consommé (comme sur les abonnements Internet mobile en France), par
exemple, on peut avoir envie d'envoyer des mises à jour plus fréquentes afin de
prévenir plus rapidement le client qu'il va/a dépasser son forfait et/ou afin
d'avoir une granularité permettant de ne pas se faire gruger. Une actualisation
plus fréquente suppose un bon dimensionnement du serveur RADIUS qui devra
écrire, sur un support de stockage, chaque ticket d'accounting correspondant à
chaque client Wi-Fi. Dans le cadre de ce TP, une actualisation plus fréquente
n'est pas pertinente, mais la mise en œuvre de celle-ci est intéressante à
découvrir.

Il existe un attribut RADIUS pour conseiller à un NAS un délai entre chaque
actualisation : « Acct-Interim-Interval ». PepperSpot en tient compte, notre
borne Cisco non. La liste des attributs RADIUS pris en charge par notre Aironet
est disponible en ligne. La liste des attributs RADIUS normalisés (en dehors des
attributs spécifiques à des vendeurs) est disponible sur le site web de l'IANA.

Sur notre Aironet, il faut utiliser la commande suivante pour activer
l'actualisation fréquente de l'accounting :

aaa accounting update periodic <delai_en_minutes>

On notera également que, sur notre Cisco Aironet, il faut parfois saisir des
commandes pour activer la prise en compte de certains attributs RADIUS. Exemple
: « dot1x timeout reauth-period server » pour indiquer à la borne de prendre en
considération l'attribut « Session-Timeout » qui indique la durée maximale de la
connexion d'un client avant réauthentification (on trouve cela dans les gares,
les aéroports et sur les hotspots payants où l'on peut acheter 10 minutes, 30
minutes, 1 heure d'accès). En 2016, je trouve cela parfaitement idiot : RADIUS
existe pour centraliser l'authentification et l'autorisation. S'il faut saisir
une commande sur chacun de nos AP pour activer la prise en compte de chaque
attribut RADIUS sur chaque équipement réseau, autant de pas utiliser RADIUS et
pousser toute la config' sur chaque AP.

… ET DISPARITION SUBITE D'UN CLIENT WI-FI

Un autre attribut RADIUS est intéressant : « Idle-Timeout ». Il permet de
déconnecter un client Wi-Fi en cas d'inactivité constatée au niveau du trafic
réseau émis. Forcément, il n'est pas pris en charge par notre Cisco Aironet,
mais il est pris en charge par PepperSpot. Ce n'est pas grave puisqu'en cas de
déconnexion/reconnexion, notre Cisco Aironet se rend compte que la précédente
connexion a été coupée et émet un Accounting-Stop pour cette connexion. En
revanche, si un client quitte la zone de couverture de notre AP (ou réseau d'AP)
sans s'être déconnecté au préalable (notamment sur le portail captif), alors
aucun Accounting-Stop n'est émis et l'on obtient une connexion zombie dans notre
accounting RADIUS. C'est dans ce genre de cas que l'attribut « Idle-Timeout »
est intéressant.

COMMENT AJOUTER UN ATTRIBUT DE RÉPONSE DANS UNE RÉPONSE RADIUS ?

Les attributs qui nous intéressant s'appliquent à l'ensemble de nos
utilisateurs. Il faut donc les ajouter dans la définition de chaque utilisateur
dans notre fichier users ou dans notre base de données. Trop chiant et
redondant. On peut créer des groupes, leur appliquer nos attributs et attribuer
ces groupes à nos utilisateurs. Trop chiant. Il existe un utilisateur, « DEFAULT
» qui matche toujours, pour tout identifiant. Utilisons ça.

Dans notre fichier /etc/freeradius/users, avant toute définition d'un quelconque
utilisateur réel, ajoutons ceci :

DEFAULT	
	Acct-Interim-Interval := 120,
	Idle-Timeout := 600

On positionne le délai max entre deux actualisations à 2 minutes et on
positionne la clôture d'une connexion zombie après 10 minutes d'inactivité.

Si vous utilisez le module « sql » pour remonter les informations sur les
utilisateurs de votre réseau Wi-Fi, alors les modules « files » et « sql » sont
complémentaires : chacun apportera sa part de la réponse finale.

Si vous utilisez uniquement le module « files », il y a une petite méchanceté :
ce module s'arrête à la première occurrence trouvée. Il s'arrêtera donc à
l'utilisateur DEFAULT et rejettera donc votre utilisateur. Pour pas que cela se
produise, il faut ajouter l'attribut de contrôle « Fall-Through := yes » à la
fin de la définition de l'utilisateur DEFAULT.

Si vous voulez utiliser uniquement MySQL, c'est un peu plus compliqué : il faut
utiliser un « default user profile » c'est-à-dire un utilisateur qui fait partie
d'un groupe auquel seront appliqués les attributs de réponse désirés. Par
défaut, l'identifiant de cet utilisateur est « default ». Pour créer ce profile,
il faut exécuter ces deux requêtes SQL :

INSERT INTO radusergroup(groupname, priority, username) VALUES('defaultgroup', 1, 'DEFAULT');
INSERT INTO radgroupreply(id, groupname, attribute, op, VALUE) VALUES((1, 'defaultgroup', 'Idle-Timeout', ':=', '600'), (2, 'defaultgroup', 'Acct-Interim-Interval', ':=',  '120'));

Puis, dans /etc/freeradius/sql/mysql/dialup.conf, il faut décommenter la ligne «
default_user_profile = "DEFAULT" et redémarrer freeRADIUS.

ATTRIBUTS DE RÉPONSE ET SUBTILITÉ EAP-TTLS

Lors d'un échange EAP-TTLS, les attributs de réponse seront insérés dans la
réponse « Access-Challenge » qui suit un « Access-Request », c'est-à-dire qu'ils
seront insérés durant l'initialisation du tunnel TLS. Or, ce tunnel est de bout
en bout, entre le serveur RADIUS et le client Wi-Fi, alors que nos attributs
sont destinés au NAS de l'AP Wi-Fi ! Dans le cas de PepperSpot, il est NAS et
utilisateur final à la fois et il n'y a pas de tunnel TLS donc il voit bien les
attributs et les prend en compte. Mais pas notre AP Cisco qui est un
intermédiaire.

De même, lorsqu'on utilise EAP-TTLS, le véritable identifiant de l'utilisateur
de notre réseau Wi-Fi circule uniquement à l'intérieur du tunnel chiffré. Or, le
NAS utilise l'identifiant retourné par le serveur RADIUS lors de
l'authentification dans ses requêtes d'accounting. Il s'agit donc de
l'identifiant hors tunnel TLS, donc d'un identifiant bidon, bien souvent. C'est
conçu pour cela, afin d'éviter que le vrai identifiant circule sur le réseau
Wi-Fi, ce qui permet aisément le pistage (qui était connecté à notre réseau
Wi-Fi de telle heure à telle heure ?) puisque tout le monde peut capter le
trafic Wi-Fi non chiffré ou chiffré avec une clé commune comme c'est le cas d'un
réseau WPA(2) PSK.

Pour résoudre ces deux problèmes, il faut demander au serveur RADIUS de copier
les attributs de réponse qu'il a positionnés dans le tunnel TLS pour les
positionner en dehors du tunnel. Cela se fait dans la configuration du module «
ttls », dans le fichier /etc/freeradius/eap.conf, en positionnant la valeur de «
use_tunneled_reply » à « yes ». Pour que le bon identifiant apparaisse dans le
message « Access-Accept » et donc dans l'accounting, il faut également ajouter
la ligne suivante dans les attributs de réponse de l'utilisateur DEFAULT :

User-Name := "%{User-Name}"

Il n'y a pas de risques pour la vie privée, sauf si le lien réseau entre le
serveur RADIUS et les AP n'est pas isolé du reste du réseau (mais alors, vous
avez un problème bien plus grave). L'identifiant en clair circule uniquement sur
ce lien, par entre l'AP et le client Wi-Fi.

STOCKAGE DE L'IPV6 DES TICKETS D'ACCOUNTING

Nous avons vu que notre portail captif envoie les IP (v4 et v6) de nos clients
Wi-Fi dans ses requêtes d'accounting. Seulement, freeRADIUS stocke uniquement
l'IPv4 dans notre base de données. Ça n'a à peu près aucun sens de stocker
l'IPv6 de nos clients compte tenu que PepperSpot accepte uniquement qu'ils
utilisent une IPv6 dérivée de leur adresse MAC mais, c'est utile pour découvrir
l'envers du décor.

Pour ce faire, il est nécessaire de changer le schéma de la table « radacct »
pour ajouter deux colonnes (une pour le préfixe IPv6 du réseau, une pour la
partie "machine" de l'IPv6). Voici les requêtes SQL à utiliser :

ALTER TABLE radacct ADD COLUMN framedipv6prefix VARCHAR(25) NOT NULL DEFAULT '' AFTER framedipaddress;
ALTER TABLE radacct ADD COLUMN framedinterfaceid VARCHAR(25) NOT NULL DEFAULT '' AFTER framedipv6prefix;

Ensuite, il faut modifier la requête SQL utilisée par freeRADIUS pour réaliser
l'accounting. Cela se passe dans le fichier
/etc/freeradius/sql/mysql/dialup.conf. La requête à modifier se nomme «
accounting_start_query ». Il faut la modifier comme cela :

INSERT INTO ${acct_table1} \
(acctsessionid,    acctuniqueid,     username, \
 realm,            nasipaddress,     nasportid, \
 nasporttype,      acctstarttime,    acctstoptime, \
 acctsessiontime,  acctauthentic,    connectinfo_start, \
 connectinfo_stop, acctinputoctets,  acctoutputoctets, \
 calledstationid,  callingstationid, acctterminatecause, \
 servicetype,      framedprotocol,   framedipaddress, \
 framedipv6prefix, framedinterfaceid, \
 acctstartdelay,   acctstopdelay,    xascendsessionsvrkey) \
VALUES \
('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', \
 '%{SQL-User-Name}', \
 '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port}', \
 '%{NAS-Port-Type}', '%S', NULL, \
 '0', '%{Acct-Authentic}', '%{Connect-Info}', \
 '', '0', '0', \
 '%{Called-Station-Id}', '%{Calling-Station-Id}', '', \
 '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', \
 '%{Famed-IPv6-Prefix}', '%{Framed-Interface-id}', \
 '%{%{Acct-Delay-Time}:-0}', '0', '%{X-Ascend-Session-Svr-Key}')"

On redémarre freeRADIUS et c'est prêt. \o/

Au passage, on notera que PepperSpot ouvre deux tickets d'accounting, un avec
l'IPv4, l'autre avec l'IPv6 du client Wi-Fi et qu'un seul des tickets contient
l'identifiant : celui qui contient l'IP qui a servi à accéder à la page
d'authentification. Ce n'est donc pas terrible pour retrouver une association
MAC<->identifiant sur des machines clientes mutualisées (genre les salles de TP)
car il n'y pas de valeurs en commun. Il faut faire un croisement en prenant un
triplet MAC (calling station ID) + Starttime/Stoptime (il diffère d'au plus une
seconde entre les deux tickets) et le session-id (qui est incrémenté d'au plus
une unité entre les deux tickets).

MÉNAGE RÉGULIER

Toutes les données de connexion doivent être conservées un an, pas plus, pas
moins. Il est donc important de purger régulièrement l'accounting RADIUS.
DaloRADIUS propose une telle option dans son interface, mais il est inhumain de
réaliser cette opération tous les jours ou même tous les mois.

Du coup, laissons ça à cron en ajoutant ceci dans la crontab de root pour un
ménage quotidien :

crontab -e
0 0 * * * echo "DELETE FROM radacct where TIMESTAMPDIFF(YEAR, acctstarttime, NOW()) >=1;" | mysql -u radius -p<mdp> radius

Pour les personnes qui s'offusquent de stocker un mdp dans la crontab de root,
rappelons que sous Debian, il existe un utilisateur MySQL, « debian-sys-maint »,
qui a accès en écriture à toute base de données MySQL et dont le mdp est
accessible à root depuis /etc/mysql/debian.cnf. Rappelons aussi que qui à accès
au compte root a accès à tout, de toute façon.

Calculer à partir de starttime permet de virer également les connexions
interrompues brutalement.

OUTRO

On se rend compte que l'accounting RADIUS a quelques limites franches : il est
agnostique au protocole de couche 3 donc il faut conserver ailleurs
l'association entre couche 3 et couche 2, et ce qu'il est possible de faire
dépend vraiment des implémentations des NAS. :/

LOGS DHCP

Sur TESTAP, c'est PepperSpot qui fait office de serveur DHCPv4. Sur TESTAP-sec,
c'est l'implémentation de l'ISC que nous avons configurée. Dans tous les cas, il
n'y a pas d'allocations d'adresses stateful avec DHCPv6. Dans les deux cas, les
allocations effectuées sont journalisées dans les fichiers syslog et daemon.log.
Nous allons voir ici comment trier nos logs et garantir leur effacement au-delà
d'un an.

On install rsyslog (syslog propose aussi des filtres mais leur syntaxe me pique
un peu plus les yeux) :

sudo apt-get install rsyslog logrotate

On crée un fichier /etc/rsyslog.d/dhcpd.conf avec le contenu suivant :

if $programname == 'dhcpd' then /var/log/dhcp/dhcpd.log
& ~
 
if $programname == 'pepperspot' then /var/log/dhcp/dhcpd.log
& ~

Tout ce qui est émit par PepperSpot et par notre serveur DHCP est rangé dans
/var/log/dhcp/dhcpd.log .

On fait prendre en compte la nouvelle configuration par rsyslog :

sudo systemctl restart rsyslog

On crée un fichier /etc/logrotate.d/dhcpd avec le contenu suivant :

/var/log/dhcpd.log {
    monthly
    missingok
    rotate 12
    compress
    delaycompress
    ifempty
    create 640 root adm
    sharedscripts
    olddir /var/log/archives/dhcpd
    postrotate
        service rsyslog rotate > /dev/null
    endscript
}

Il est de notre ressort de créer le dossier d'archivage /var/log/archives/dhcpd
:

sudo mkdir -p /var/log/archives/dhcpd

JOURNALISER LES ASSOCIATIONS MAC<->IP

On installe les deux logiciels KiVontBien :

sudo apt-get install arpwatch ndpmon

Dans /etc/default/arpwatch, il faut ajouter « -Q » à la variable « ARGS » pour
demander à arpwatch de ne pas envoyer d'emails à chaque événement suspect, car
ce n'est pas l'usage que nous attendons d'arpwatch dans ce contexte.

Par défaut, arpwatch est actif uniquement sur eth0. Il faut ajouter les
interfaces supplémentaires (testap et tapsec, dans notre cas) dans
/etc/arpwatch.conf.

On redémarre arpwatch pour qu'il prenne en compte la nouvelle configuration :

sudo systemctl restart arpwatch

ndpmon ne nécessite pas de configuration particulière.

Comme pour les logs DHCP, nous trions nos logs avec rsyslog en ajoutant un
fichier /etc/rsyslog.d/arp-ndp-watch.conf avec le contenu suivant :

if $programname == 'arpwatch' then /var/log/assocs/mac-ipv4.log
& ~
 
if $programname == 'NDPMon' then /var/log/assocs/mac-ipv6.log
& ~

Il est de notre ressort de créer le dossier de stockage des logs /var/log/assocs
:

sudo mkdir /var/log/assocs

On fait prendre en compte la nouvelle configuration par rsyslog :

sudo systemctl restart rsyslog

De la même manière, nous configurons logrotate avec un fichier
/etc/logrotate.d/arp-ndp-watch avec le contenu suivant :

/var/log/assocs/*.log {
    monthly
    missingok
    rotate 12
    compress
    delaycompress
    ifempty
    create 640 root adm
    sharedscripts
    olddir /var/log/archives/assocs/
    postrotate
        service rsyslog rotate > /dev/null
    endscript
}

Il est de notre ressort de créer le dossier d'archivage
/var/log/archives/assocs/ :

sudo mkdir -p /var/log/archives/assocs/

ADMINISTRATION, SUPERVISION, TYPES DE FLUX

SUPERVISION

On installe Monit :

sudo apt-get install moni monitoring-plugins

Il faut activer le démon HTTP dans /etc/monit/monitrc. Nous n'activons pas les
alertes emails dans ce même fichier, c'est volontaire : nous trouvons cela
inutile dans le cadre de ce TP.

Il faut créer les fichiers de conf' qui définissent nos services dans
/etc/monit/conf.d/ . Nos configs sont copiés/inspirées du wiki officiel Monit.

ap :

 check host AP-Cisco with address 198.18.255.1
   if failed icmp type echo with timeout 5 seconds then alert
   if failed port 161 type udp then alert

apache2 :

 check process apache with pidfile /var/run/apache2/apache2.pid
   group www
   group apache
   start program = "/etc/init.d/apache2 start"
   stop program  = "/etc/init.d/apache2 stop"
   if failed host 127.0.0.1 port 443 with protocol https and request "/" with timeout 10 seconds for 4 times within 5 cycles then alert
   depend apache_bin
   depend apache_rc
 
 check file apache_bin with path /usr/sbin/apache2
   group apache
   include /etc/monit/templates/rootbin
 
 check file apache_rc with path /etc/init.d/apache2
   group apache
   include /etc/monit/templates/rootbin

FreeRADIUS :

 check process freeradius with pidfile /var/run/freeradius/freeradius.pid
   start program = "/etc/init.d/freeradius start"
   stop program = "/etc/init.d/freeradius stop"
   if failed host 127.0.0.1 port 1812 type udp protocol radius secret <secret_radius> then alert
   if failed host 127.0.0.1 port 1813 type udp protocol radius secret <secret_radius> then alert

MySQL :

 check process mysqld with pidfile /var/run/mysqld/mysqld.pid
   group database
   group mysql
   start program = "/etc/init.d/mysql start"
   stop  program = "/etc/init.d/mysql stop"
   if failed host localhost port 3306 protocol mysql with timeout 5 seconds for 3 times within 4 cycles then alert
   if failed unixsocket /var/run/mysqld/mysqld.sock protocol mysql for 3 times within 4 cycles then alert
   depend mysql_bin
   depend mysql_rc
 
 check file mysql_bin with path /usr/sbin/mysqld
   group mysql
   include /etc/monit/templates/rootbin
 
 check file mysql_rc with path /etc/init.d/mysql
   group mysql
   include /etc/monit/templates/rootbin

NTPd :

 check process ntpd with pidfile /var/run/ntpd.pid
   start program = "/etc/init.d/ntp start"
   stop  program = "/etc/init.d/ntp stop"
   if failed host 127.0.0.1 port 123 type udp then alert
   if 5 restarts within 5 cycles then timeout

rsyslog :

 check process rsyslogd with pidfile /var/run/rsyslogd.pid
   group system
   group rsyslogd
   start program = "/etc/init.d/rsyslog start"
   stop  program = "/etc/init.d/rsyslog stop"
   depend on rsyslogd_bin
   depend on rsyslogd_rc
   depend on rsyslog_file
 
 check file rsyslogd_bin with path /usr/sbin/rsyslogd
   group rsyslogd
   include /etc/monit/templates/rootbin
 
 check file rsyslogd_rc with path "/etc/init.d/rsyslog"
   group rsyslogd
   include /etc/monit/templates/rootbin
 
 check file rsyslog_file with path /var/log/syslog
   group rsyslogd
   if timestamp > 65 minutes then alert
   if failed permission 640  then unmonitor
   if failed uid root        then unmonitor
   if failed gid adm         then unmonitor

dhcpd4 :

check process isc-dhcp-server with pidfile /var/run/dhcpd.pid

dhcpd6 :

check process isc-dhcp6-server with pidfile /var/run/dhcpv6/dhcpdv6.pid

On redémarre monit afin de prendre en compte les nouveaux checks à réaliser :

sudo systemctl restart monit

L'interface web de monit est désormais accessible en http://127.0.0.1:2812/ .
Cette page est uniquement consultable depuis localhost car cela est défini dans
la configuration et que notre pare-feu bloque les connexions entrantes.

MÉTROLOGIE

On installe munin :

sudo apt-get install munin munin-node

Nous n'avons rien d'autre à faire : l'interface web de Munin est accessible en
http://[::1]/munin et elle présente les métriques qui nous intéressent (trafic
réseau, IO, charge CPU, etc.). Cette page est uniquement consultable depuis
localhost car cela est défini dans la configuration et que notre pare-feu bloque
les connexions entrantes.

TYPOLOGIE DES FLUX RÉSEAUX

On installe ntop-ng :

sudo apt-get install ntopng

Il n'y a rien d'autre à faire : l'interface web de ntop-ng est accessible en
http://127.0.0.1:3000 avec le couple identifiant/mdp admin/admin. Cette page est
uniquement consultable depuis localhost car notre pare-feu bloque les connexions
entrantes.

ZONE D'ADMINISTRATION

On crée une place pour notre page web d'administration dans le DocumentRoot
d'Apache :

sudo rm -r /var/www/*
sudo mkdir /var/www/admin
sudo chown www-data:www-data /var/www/admin

On modifie le virtualhost Apache de PepperSpot,
/etc/apache2/sites-enabled/pepperspot.conf, pour ajouter une authentification
pour toute la zone d'administration :

<Directory /var/www/admin>
    AuthName "Olympe"
    AuthType Basic
    AuthUserFile "/etc/apache2/htpasswd"
    Require valid-user
</Directory>

On ajoute un utilisateur autorisé dans le fichier htpasswd (qui peut être nommé
différemnent, d'ailleurs) :

sudo htpasswd -c /etc/apache2/htpasswd <identifiant>

GESTION DE LA BASE DE DONNÉES RADIUS

On crée une place pour daloRADIUS et on l'y extrait :

cd /var/www/admin
sudo tar xf $HOME/daloradius-0.9.9.tar.gz
sudo mv daloradius-0.9-9 daloradius
sudo chown -R www-data:www-data daloradius
sudo chmod 6400 daloradius/library/daloradius.conf.php

Il faut ensuite lire le manuel (le fichier « INSTALL ») et installer les
dépendances requises :

sudo apt-get install libapache2-mod-php5 php5-gd php-pear php-db php-mail php5-mysql

Puis, il faut enrichir la base de données de FreeRADIUS avec les tables de
daloRADIUS :

mysql -u radius -p radius < daloradius/contrib/db/mysql-daloradius.sql

Enfin, il faut configurer les paramètres d'accès à la base de données dans
daloradius/library/daloradius.conf.php .

L'interface web de daloRADIUS est désormais disponible en
http://[::1]/admin/daloradius/ . Elle est accessible avec le couple
identifiant/mdp administrator/radius.

Par défaut, daloRADIUS n'affiche pas les IPv6. Il est possible de patcher une
partie des pages « acct-* » pour afficher l'information désirée. Notre patch est
disponible ici : daloradius-ipv6.patch.

DaloRADIUS ne prend pas en charge SHA1 malgré ce qui est indiqué dans
l'interface web (le mdp sera bel et bien stocké en clair). Pour corriger cela,
il faut ajouter ce qui suit ligne 440 de mng-new.php (rien n'est implémenté dans
mng-new-quick.php, pas même MD5 donc nous ne nous sommes pas occupés de ce
fichier…) :

} elseif (preg_match("/sha1/i", $passwordtype)) {
    $dbPassword = "SHA1('$password')";
}

SNMP

Comme annoncé plus haut, nous utilisons SNMP pour remonter quelques infos
pertinentes depuis notre AP.

SNMPD SUR NOTRE CISCO AIRONET

Voici les commandes à utiliser pour activer SNMP sur notre AP Cisco :

access-list 1 permit 198.18.255.0
snmp-server community <nom_idiot_de_la_communauté_SNMP> RO 1

Oui, il est nécessaire d'utiliser un numéro pour désigner l'access-list.

OIDs intéressants :

 * Uptime : 1.3.6.1.2.1.1.3.0
 * Load average (en pourcentage). Sur les 5 dernières secondes :
   1.3.6.1.4.1.9.9.109.1.1.1.1.6.1 ; Sur la dernière minute :
   1.3.6.1.4.1.9.9.109.1.1.1.1.7.1 ; Sur les 5 dernières minutes :
   1.3.6.1.4.1.9.9.109.1.1.1.1.8.1
 * RAM (octets). Libre : 1.3.6.1.4.1.9.9.48.1.1.1.6.1 ; Occupée :
   1.3.6.1.4.1.9.9.48.1.1.1.6.1
 * Nombre total de clients Wi-Fi associés depuis le boot :
   1.3.6.1.4.1.9.9.273.1.1.3.1.1.1
 * Nombre total de clients Wi-Fi authentifiés depuis le boot :
   1.3.6.1.4.1.9.9.273.1.1.3.1.2.1
 * Nombre de clients Wi-Fi associés en ce moment (authentifiés ou non) :
   1.3.6.1.4.1.9.9.273.1.1.2.1.1.1

SNMPD SUR NOTRE WRT54GL AVEC OPENWRT

D'abord, il faut installer un démon snmpd. J'ai choisi snmpd, la version
complète que l'on retrouve partout sous GNU/Linux :

opkg update && opkg install snmpd

Ensuite, il faut configurer ce démon dans /etc/config/snmp. Voici ma
configuration complète :

config agent
        option agentaddress UDP:161
 
config com2sec public
        option secname ro
        option source 198.18.255.0
        option community <nom_idiot_communauté>
 
config group public_v2c
        option group public
        option version v2c
        option secname ro
 
config view all
        option viewname all
        option type included
        option oid .1
 
config access public_access
        option group public
        option context none
        option version any
        option level noauth
        option prefix exact
        option read all
        option write none
        option notify none
 
config system
        option sysLocation      'test'
        option sysContact       'test@example.com'
        option sysName          'testap'

Enfin, on redémarre snmpd :

/etc/init.d/snmpd restart

OIDs intéressants :

 * Uptime : iso.3.6.1.2.1.25.1.1.0
 * RAM. Total : iso.3.6.1.2.1.25.2.3.1.5.1 ; Occupée :
   iso.3.6.1.2.1.25.2.3.1.6.1

Pour avoir le nombre de clients Wi-Fi associés en ce moment, il faut bricoler un
peu :

mkdir -p /usr/local/bin

Dans un fichier /usr/local/bin/wlassocs.sh, mettre le contenu suivant :

#!/bin/sh
wlc assoclist | sed '/^$/d' | wc -l | sed 's/ //g'

Penser à rendre ce script exécutable :

chmod +x /usr/local/bin/wlassocs.sh

Ajouter le bout de config' qui suit dans /etc/config/snmp (l'OID est totalement
arbitraire) :

config exec
        option name     wlassocs
        option prog     /usr/local/bin/wlassocs.sh
        option miboid   .1.3.6.1.2.1.2.2.1.50

On redémarre snmpd et le nombre clients Wi-Fi sera disponible en
iso.3.6.1.2.1.2.2.1.50.1.1 \o/

PAGE D'ADMINISTRATION

Notre page est une simple page PHP qui réalise des requêtes SNMP et SQL pour
récupérer des informations sur notre AP Wi-FI et pour récupérer les informations
sur les utilisateurs connectés à nos réseaux Wi-Fi depuis l'accounting RADIUS.
Elle fait également le lien avec les outils de gestion et de supervision que
nous avons déployé.

Pour réaliser des requêtes SNMP depuis PHP, il faut installer le module SNMP
pour avoir accès à la classe SNMP :

sudo apt-get install php5-snmp

Le reste, c'est du PHP classique :

<?php
	$AP_IP                  = '198.18.255.1';
	$AP_SNMP_COMMUNITY	= '<communauté_SNMP>';
 
	// Sans le masque du réseau
	$IPv6_PREFIX            = '2001:470:c8d6:2:';
 
	$DB_HOST                = 'localhost';
	$DB_NAME                = 'radius';
	$DB_USER                = 'radius';
	$DB_PWD                 = '<mdp>';
?>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 
	<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>Page d'administration réseau sans fil sécurisé et monitoré</title>
	</head>
 
	<body>
		<h1>Quelques infos sur le point d'accès (SNMP) : </h1>
 
			<?php
				$snmp = new SNMP(SNMP::VERSION_2C, $AP_IP , $AP_SNMP_COMMUNITY, 5000, 1); // timeout = 5 secs, 1 seul essai.
				$snmp->quick_print = 1; // Ne pas afficher autre chose que la valeur des OID remontés
			?>
 
			Uptime du point d'accès Cisco (jours:heures:minutes:secondes.ms) : <?php echo @$snmp->get('1.3.6.1.2.1.1.3.0'); ?>
 
			<br/>Charge CPU du point d'accès Cisco (5 secs, 1 minute, 5 minutes, en pourcentage) : <?php echo @$snmp->get('1.3.6.1.4.1.9.9.109.1.1.1.1.6.1')
			.' '.@$snmp->get('1.3.6.1.4.1.9.9.109.1.1.1.1.7.1').' '.@$snmp->get('1.3.6.1.4.1.9.9.109.1.1.1.1.8.1'); ?>
 
			<br />Mémoire (octets) : libre = <?php echo @$snmp->get('1.3.6.1.4.1.9.9.48.1.1.1.6.1').' | occupée (octets) : '.@$snmp->get('1.3.6.1.4.1.9.9.48.1.1.1.5.1'); ?>
 
 
			<br /><br /> Nombre total de clients Wi-Fi associés depuis le boot : <?php echo @$snmp->get('1.3.6.1.4.1.9.9.273.1.1.3.1.1.1'); ?>
 
			<br/> Nombre total de clients Wi-Fi authentifiés depuis le boot : <?php echo @$snmp->get('1.3.6.1.4.1.9.9.273.1.1.3.1.2.1'); ?>
 
			<br/> Nombre de clients Wi-Fi associés en ce moment (authentifiés ou non) : <?php echo @$snmp->get('1.3.6.1.4.1.9.9.273.1.1.2.1.1.1'); ?>
 
 
		<br /><br />
		<h1>Utilisateurs authentifiés</h1>
		<?php
			try
			{
				$bdd = new PDO("mysql:host=$DB_HOST;dbname=$DB_NAME", $DB_USER, $DB_PWD);
			}
			catch(Exception $e)
			{
				die('Erreur : '.$e->getMessage());
			}
		?>
 
 
		<h2>TESTAP :</h2>
		<table style="border-collapse: collapse;">
		<tr>
			<th style="border: 1px solid black;">Identifiant</th>
			<th style="border: 1px solid black;">Adresse MAC</th>
			<th style="border: 1px solid black;">Adresse IPv4</th>
			<th style="border: 1px solid black;">Adresse IPv6</th>
			<th style="border: 1px solid black;">Début</th>
			<th style="border: 1px solid black;">Durée (secondes)</th>
			<th style="border: 1px solid black;">Octets reçus</th>
			<th style="border: 1px solid black;">Octets émis</th>
		</tr>
 
		<?php
			// On récupére les personnes connectées sur TESTAP (NAS = '' car Pepperspot ne stocke pas d'IP...), 
			// dont la session est encore en cours (acctstoptime IS null) depuis moins de 6h (une journée de taff universitaire, en gros) 
			// afin d'éviter d'afficher les sessions mal fermées qui resteront sans accounting stop pour toujours.
			$reponse = $bdd->query('SELECT username, callingstationid, framedipaddress, framedinterfaceid, acctstarttime, acctsessiontime, acctinputoctets, acctoutputoctets 
									FROM radacct 
									WHERE nasipaddress = "" AND acctstoptime IS null AND TIMESTAMPDIFF(HOUR, acctstarttime, NOW()) < 6;');
 
			while ($donnees = $reponse->fetch())
			{
			?>
				<tr>
					<td style="border: 1px solid black;"><?php echo $donnees['username']; ?></td>
					<td style="border: 1px solid black;"><?php echo $donnees['callingstationid']; ?></td>
					<td style="border: 1px solid black;"><?php if(!empty($donnees['framedipaddress'])) echo '<a href="http://localhost:3000/lua/host_details.lua?host='.$donnees['framedipaddress'].'">'.$donnees['framedipaddress'].'</a>'; ?></td>
					<td style="border: 1px solid black;"><?php if(!empty($donnees['framedinterfaceid'])) echo '<a href="http://localhost:3000/lua/host_details.lua?host='.$IPv6_PREFIX.$donnees['framedinterfaceid'].'">'.$IPv6_PREFIX.$donnees['framedinterfaceid'].'</a>'; ?></td>
					<td style="border: 1px solid black;"><?php echo $donnees['acctstarttime']; ?></td>
					<td style="border: 1px solid black;"><?php echo $donnees['acctsessiontime']; ?></td>
					<td style="border: 1px solid black;"><?php echo $donnees['acctinputoctets']; ?></td>
					<td style="border: 1px solid black;"><?php echo $donnees['acctoutputoctets']; ?></td>
				</tr>
			<?php
			}
 
			$reponse->closeCursor();
		?>
		</table>
 
 
		<h2>TESTAP-sec :</h3>
		<table style="border-collapse: collapse;">
		<tr>
			<th style="border: 1px solid black;">Identifiant</th>
			<th style="border: 1px solid black;">Adresse MAC</th>
			<th style="border: 1px solid black;">Début</th>
			<th style="border: 1px solid black;">Durée (secondes)</th>
			<th style="border: 1px solid black;">Octets reçus</th>
			<th style="border: 1px solid black;">Octets émis</th>
		</tr>
 
		<?php
			$reponse = $bdd->query('SELECT username, callingstationid, acctstarttime, acctsessiontime, acctinputoctets, acctoutputoctets
						FROM radacct
						WHERE nasipaddress="198.18.255.1" AND acctstoptime IS null AND TIMESTAMPDIFF(HOUR, acctstarttime, NOW()) < 6;');
 
			while ($donnees = $reponse->fetch())
			{
			?>
				<tr>
					<td style="border: 1px solid black;"><?php echo $donnees['username']; ?></td>
					<td style="border: 1px solid black;"><?php echo $donnees['callingstationid']; ?></td>
					<td style="border: 1px solid black;"><?php echo $donnees['acctstarttime']; ?></td>
					<td style="border: 1px solid black;"><?php echo $donnees['acctsessiontime']; ?></td>
					<td style="border: 1px solid black;"><?php echo $donnees['acctinputoctets']; ?></td>
					<td style="border: 1px solid black;"><?php echo $donnees['acctoutputoctets']; ?></td>
				</tr>
			<?php
			}
 
			$reponse->closeCursor();
		?>
		</table>
 
 
		<br /><br />
		<h1>Ressources : </h1>
		<a href="/admin/daloradius">DaloRADIUS</a> (créer/supprimer un utilisateur, accès accounting RADIUS, ...)<br/>
		<a href="http://localhost:3000/">Ntop-ng</a> (visualiser l'activité réseau) <br/>
		<a href="http://localhost:2812/">Monit</a> (supervision des services) <br/>
		<a href="/munin/">Munin</a> (metrologie de la machine locale) <br/>
 
		<br /><br />
		<h1>Rappels :</h1>
		Les logs DHCP (TESTAP-sec) et DHCPv6 (*) sont disponibles dans les fichiers /var/log/dhcpd.log et /var/log/archives/dhcpd/<br/>
		Les logs des associations MAC<->IP(v6) sont disponibles dans les fichiers /var/log/assocs/mac-ip(v4|v6).log et /var/log/archives/assocs/<br/>
 
		Visualiser/modifier le pare-feu : iptables - ip6tables
	</body>
</html>

Les « @ » disgracieux se justifient car la classe SNMP est toujours bavarde,
même si l'on utilise un try/catch ou un if/else sur la valeur de retour.
Autrement dit : il ne semble pas être possible d'afficher une erreur
personnalisée sans que l'erreur définie dans la classe s'affiche également. D'où
cette mise sous silence.

Mais si vous préférez, vous pouvez utiliser une alternative crade à la classe
SNMP comme (-Oqv permet d'afficher uniquement la valeur de l'OID remontée) :

system("/usr/bin/snmpget -Oqv -v 2c -c <communauté_snmp> 198.18.255.1 1.3.6.1.2.1.1.3.0");

Notre page d'administration est accessible en https://[::1]/admin/index.php .

MOBILITÉ IPV6

L'implémentation de la mobilité IPv6 se décompose en deux : une prise en charge
de la mobilité IPv6 par le noyau et un démon userland.

CÔTÉ NOYAU

Celui packagé dans Debian est compilé avec la prise en charge de la mobilité
IPv6 :

curl http://www.umip.org/docs/umip-install.html 2>/dev/null | grep -oE "CONFIG_[A-Z0-9_]*" | xargs -I{} grep {}= /boot/config-3.11-2-amd64

Dans la sortie de cet enchaînement de commandes, tout doit être à « y » ou à « m
» ou même à « n » pour IPSec puisque nous ne l'utiliserons pas ici.

CÔTÉ USERLAND

Le paquet umip disponible dans le dépôt apt du projet possède des dépendances
impossibles à satisfaire depuis un Debian GNU/Linux amd64 multiarch. On va donc
préférer compiler à partir des sources.

Le dépôt git du projet n'est plus accessible depuis plusieurs années
semble-t-il. Une ancienne version d'umip est disponible sur Github :
https://github.com/jlanza/umip/.

Installons les paquets nécessaires à la compilation :

sudo apt-get install make build-essential indent linux-headers-amd64 autoconf bison flex

La compilation et l'installation ne posent pas de problème particulier :

autoreconf -i
CPPFLAGS='-isystem /usr/include/' ./configure --enable-vt
make
sudo make install

Nous stockons la configuration de notre mobile node, adaptée du site web
officiel d'umip, dans /usr/local/etc/mip6d.conf :

# Sample UMIP configuration file for a MIPv6 Mobile Node
NodeConfig MN;
 
# Set DebugLevel to 0 if you do not want debug messages
DebugLevel 10;
 
# Enable the optimistic handovers
OptimisticHandoff enabled;
 
# Disable RO with other MNs (it is not compatible
# with IPsec Tunnel Payload)
DoRouteOptimizationMN disabled;
 
# The Binding Lifetime (in sec.)
MnMaxHaBindingLife 60;
 
# List here the interfaces that you will use
# on your mobile node. The available one with
# the smallest preference number will be used.
Interface "wlan0" {
    MnIfPreference 2;
}
 
# Replace eth0 with one of your interface used on
# your mobile node
MnHomeLink "wlan0" {
    HomeAgentAddress 2001:660:4701:f055:ffff::1;
    HomeAddress 2001:660:4701:f055:ffff::1012/64;
}
 
# Enable IPsec static keying
UseMnHaIPsec disabled;
KeyMngMobCapability disabled;

« 2001:660:4701:f055:ffff::1 » est l'adresse IPv6 pour établir une communication
avec notre Home Agent et « 2001:660:4701:f055:ffff::1012/64 » est l'adresse que
nous sommes autorisés à utiliser en mobilité.

Oui, il n'y a pas d'IPSec, c'est volontaire, le prof' n'ayant pas configuré cela
sur le Home Agent.

On lance umip et on vérifie que cela fonctionne (se reporter à la section «
Démonstrations » pour voir ce que l'on obtient) :

sudo mip6d -c /usr/local/etc/mip6d.conf

Si cela ne fonctionne pas, peut-être y a-t-il un filtrage BCP38 sur le réseau de
votre FAI (voir la section sur la présentation de la mobilité IPv6 ci-dessus
pour plus infos) ?

Si d'aventure vous vouliez configurer un Home Agent sans IPSec, il faudrait
activer l'IPv6 forward, utiliser la configuration radvd distribuée sur le site
web officiel d'umip (en changeant juste le préfixe annoncé) et utiliser un
fichier de configuration semblable à celui-ci :

# Sample UMIP configuration file for a MIPv6 Home Agent
NodeConfig HA;
 
# Set DebugLevel to 0 if you do not want debug messages
DebugLevel 10;
 
# Replace eth0 with the interface connected to the home link
Interface "eth0";
 
# Binding information
BindingAclPolicy 2a00:5881:8110:1000::42 allow;
DefaultBindingAclPolicy deny;
 
# Enable IPsec static keying
UseMnHaIPsec disabled;
KeyMngMobCapability disabled;

« BindingAclPolicy » permet d'indiquer quelles sont les IPv6 que les mobile
nodes peuvent utiliser.


DÉMONSTRATIONS

AJOUTER UN UTILISATEUR AUTORISÉ À SE CONNECTER À NOTRE HOTSPOT

Il faut aller sur daloRADIUS : https ://localhost/admin/daloradius,
s'authentifier pour toute l'administration (admin/toor), s'authentifier dans
daloRADIUS (administrator/radius, oui, c'est le couple par défaut), cliquer sur
« Management », « Users », « New User ». Il suffit ensuite de remplir les champs
« Username » et « Password », de choisir « SHA1-Password » dans « Password Type
» puis de soumettre le formulaire.

Création d'un nouvel utilisateur dans daloRADIUS.

L'utilisateur apparaît désormais dans la liste des utilisateurs (« List Users »)
:

Listes des utilisateurs dans daloRADIUS.

L'utilisateur peut désormais se connecter à notre hotspot, de manière sécurisée
ou via le portail captif en utilisant son couple identifiant/mdp.

AUTHENTIFICATION VIA LE PORTAIL CAPTIF

IPV4

Un utilisateur se connecte à notre hotspot. Il ouvre un navigateur et tape l'URL
d'un site web accessible uniquement en v4 (exemple : ent.unistra.fr) :

Un utilisateur connecté à notre hotspot tente d'accéder à un site web accessible
uniquement en IPv4.

Il est redirigé vers notre portail captif en utilisant l'IPv4 de ce dernier :

L'utilisateur est redirigé vers la page de connexion en utilisant IPv4.

Si l'authentification échoue, il recevra un message « login failed ». Si
l'authentification réussit, l'utilisateur sera redirigé vers le site web qu'il a
demandé.

IPV6

Un utilisateur se connecte à notre hotspot. Il ouvre un navigateur et tape l'URL
d'un site web accessible en v6 (exemple : bind6.it - pastebin-like accessible
uniquement en v6) :

Un utilisateur connecté à notre hotspot tente d'accéder à un site web accessible
en IPv6.

Il est redirigé vers notre portail captif en utilisant l'IPv6 de ce dernier :

L'utilisateur est redirigé vers la page de connexion en utilisant IPv6.

Si l'authentification échoue, il recevra un message « login failed ». Si
l'authentification réussit, l'utilisateur sera redirigé vers le site web qu'il a
demandé.

AUTHENTIFICATION 802.1X

L'utilisateur scanne les réseaux Wi-Fi environnements, tente de se connecter à
notre réseau TESTAP-sec puis configure les paramètres de la connexion (TTLS,
PAP, certificat de l'AC que nous mettons à disposition, identifiant, mot de
passe) comme sur OSIRIS-sec. Sous GNU/Linux, avec GNOME, cela se configure lors
de la première connexion ou dans les paramètres avancés de GNOME Network
Manager. Sous Windows, il faudra utiliser un logiciel comme secureW2.

Paramètres 802.1X pour notre SSID TESTAP-sec avec GNOME Network Manager.

ACCOUNTING RADIUS

L'accounting RADIUS peut être consulté facilement avec daloRADIUS (voir «
Ajouter un utilisateur »). L'onglet « Accounting » permet d'accéder à toutes les
fonctionnalités : recherche par identifiant, recherche par adresse IP, recherche
par AP, historique, etc. Exemple :

Accounting RADIUS : l'utilisateur lg est connecté à TESTAP-sec depuis 57
secondes.

ADMINISTRATION & SUPERVISION

Une page web regroupant tous les outils d'administration et de supervision est
accessible en https://[::1]/admin/. Il faut s'identifier (admin/toor dans notre
cas). Cette page web affiche : des informations concernant notre point d'accès
Cisco collectées en utilisant SNMP (uptime, charge CPU, mémoire, nombre de
clients Wi-Fi associés, ...), une liste des utilisateurs connectés à notre
hotspot et des liens vers les interfaces web des autres outils d'administration
(ntop-ng, monit, munin, daloRADIUS).

Illustration de cette page web d'administration (oui, nous ne connaissons pas
CSS, et alors ? 🙂 ) :

Notre page web d'administration.

Quand l'administrateur clique sur une adresse IP, il atteint bien la page voulue
dans ntop-ng. Exemples :

Après un clic sur l'adresse IPv4 d'Hamza, on atterrit sur la page de ntop-ng qui
recense toutes les informations au sujet de cette machine et de son trafic
réseau v4.

Après un clic sur l'adresse IPv6 d'Hamza, on atterrit sur la page de ntop-ng qui
recense toutes les informations au sujet de cette machine et de son trafic
réseau v6.

Voici un aperçu de l'interface web de Monit, notre outil de supervision :

Notre interface de supervision avec Monit.

Voici un aperçu de l'interface web de Munin, notre outil de métrologie :

Notre interface de métrologie avec Munin.

MOBILITÉ IPV6

D'abord, l'utilisateur s'authentifie sur notre hotspot Wi-Fi en utilisant notre
portail captif ou l'authentification 802.1X. Ensuite, l'utilisateur peut lancer
umip en tant que mobile node avec la commande suivante lancée en root : « mip6d
-c /usr/local/etc/mip6d.conf »

Sur notre machine qui héberge le portail captif, nous capturons le trafic réseau
avec tcpdump et tshark. Nous constatons que l'initialisation s'effectue
correctement : le mobile node s'enregistre auprès de son home agent (« Binding
Update » puis « Binding Ack »).

Sur TESTAP (2001:470:c8d6:2::/64) :

  1 0.000000000 2001:470:c8d6:2:721a:4ff:feea:d429 -> 2001:660:4701:f055:ffff::1
         110 MIPv6 Binding Update
  2 1.026945000 2001:660:4701:f055:ffff::1 -> 2001:660:4701:f055:ffff::1012
         94 MIPv6 Binding Acknowledgement
  3 1.040577000 2001:470:c8d6:2:721a:4ff:feea:d429 -> 2001:660:4701:f055:ffff::1 
         86 ICMPv6 Mobile Prefix Solicitation
  4 1.061257000 2001:660:4701:f055:ffff::1 -> 2001:660:4701:f055:ffff::1012
         118 ICMPv6 Mobile Prefix Advertisement

Sur TESTAP-sec (2001:470:c8d6:3::/64) :

  1 0.000000000 2001:470:c8d6:3:721a:4ff:feea:d429 -> 2001:660:4701:f055:ffff::1
         110 MIPv6 Binding Update
  2 1.029726000 2001:660:4701:f055:ffff::1 -> 2001:660:4701:f055:ffff::1012
         94 MIPv6 Binding Acknowledgement
  3 1.035904000 2001:470:c8d6:3:721a:4ff:feea:d429 -> 2001:660:4701:f055:ffff::1
         86 ICMPv6 Mobile Prefix Solicitation
  4 1.054201000 2001:660:4701:f055:ffff::1 -> 2001:660:4701:f055:ffff::1012
         118 ICMPv6 Mobile Prefix Advertisement

Voici la sortie d'un traceroute6 depuis un client Wi-Fi avec umip en cours
d'exécution :

# traceroute6 www.google.fr
traceroute to www.google.fr (2a00:1450:4007:808::1018), 30 hops max, 
        80 byte packets
 1  2001:660:4701:f055:ffff::1 (2001:660:4701:f055:ffff::1)  
        19.783 ms  19.994 ms  20.392 ms
 2  2001:660:4701:f02f:ff::1 (2001:660:4701:f02f:ff::1)  
        21.054 ms  22.442 ms  23.055 ms
 3  2001:660:2402:9:fe:: (2001:660:2402:9:fe::)  
        23.721 ms  28.171 ms  28.011 ms
 4  vl2501-te1-3-strasbourg-rtr-021.noc.renater.fr (2001:660:7904:14:0:41:0:2200)  
        28.525 ms  28.439 ms  29.781 ms
 5  te1-2-nancy-rtr-021.noc.renater.fr (2001:660:7903:17:2::2)  
        31.251 ms  31.964 ms  34.137 ms
 6  te0-0-0-2-paris1-rtr-001.noc.renater.fr (2001:660:7903:111:1::1)  
        41.122 ms  30.286 ms  30.429 ms
 7  te0-0-0-0-paris2-rtr-001.noc.renater.fr (2001:660:7903:e:1::1)  
        33.383 ms  33.504 ms  36.780 ms
 8  te1-1-paris2-rtr-021.noc.renater.fr (2001:660:7903:3:2::2)  
        33.812 ms  35.004 ms  30.097 ms
 9  2001:660:7904:10:2::2 (2001:660:7904:10:2::2)
        30.471 ms  32.072 ms  30.507 ms
10  2001:4860::1:0:4a3a (2001:4860::1:0:4a3a)  
        32.632 ms  32.903 ms  34.101 ms
11  2001:4860:0:1::66b (2001:4860:0:1::66b)  
        34.401 ms  31.986 ms  31.961 ms
12  2a00:1450:8000:31::2 (2a00:1450:8000:31::2)  
        30.643 ms  28.606 ms  29.181 ms

That's all Folks!


Catégorie: Administration réseau, Administration système, OpenWRT, Sécurité /
Tags: aucun tag / 2 commentaires


BASCULER UNE ZONE DNS SIGNÉE D’UNE INSTANCE D’OPENDNSSEC À UNE AUTRE

Posté le 18 octobre 2014 à 22h36 par GuiGui



On a deux instances d'OpenDNSSEC, instance A et instance B, sur deux machines
différentes. L'instance A signe déjà 4 zones. L'instance B, une seule. On
souhaite factoriser et garder une seule instance OpenDNSSEC, c'est-à-dire
basculer la zone de l'instance B vers l'instance A. Le serveur DNS qui fait
autorité sur la zone ne change pas, lui, seule l'instance OpenDNSSEC derrière
change.

Évidemment, durant cette transition, il ne faut pas casser (même temporairement)
la chaîne de confiance ni faire un roulement des clés (le roulement planifié
ayant eu lieu récemment, cette solution serait possible mais sans intérêt) sinon
c'est trop facile et ce n'est pas fun.


TABLE DES MATIÈRES

 * Table des matières
 * Export des paires de clés (KSK et ZSK) depuis l'instance source (B)
 * Ajout de la zone à l'instance de destination (A)
 * Import des paires de clés (KSK et ZSK) sur l'instance de destination (A)
 * Association des clés (KSK et ZSK) à la zone sur l'instance de destination (A)
 * Divers




EXPORT DES PAIRES DE CLÉS (KSK ET ZSK) DEPUIS L'INSTANCE SOURCE (B)

La première étape est d'exporter les clés privées associées à la zone depuis le
HSM (softhsm) de l'instance B. La documentation se trouve ici : Key Management -
SoftHSM Documentation v1.3 mais elle est un peu rustique et incomplète donc on
va faire ça ensemble. 🙂

softhsm --export guiguishow.info-ksk.pem --slot 0 --pin <user_pin> --id <CKA_ID>
The key pair has been written to guiguishow.info-ksk.pem

Pour le paramètre « --pin », il faut indiquer le « USER PIN » de votre SoftHSM.
On le trouve dans /etc/opendnssec/conf.xml, au cas où 😉 .

Pour le paramètre « --id », il faut indiquer le CKA_ID de la clé à exporter.
Pour rappel, on l'obtient avec la commande :

ods-ksmutil key list --verbose

Pour la ZSK, c'est la même commande, seuls l'ID et le fichier de destination
changent.

On transfert les clés de manière sécurisée entre les machines (scp, par
exemple).


AJOUT DE LA ZONE À L'INSTANCE DE DESTINATION (A)

Dans la section « Enforcer » du fichier /etc/opendnssec/conf.xml, on décommente
« <ManualKeyGeneration/> ». Le but étant qu'OpenDNSSEC ne génère pas
automatiquement les deux paires de clés lors de l'ajout de la zone car c'est un
peu la galère pour supprimer des clés (SoftHSM + OpenDNSSEC).

On fait prendre en compte cette modification :

service opendnssec-enforcer force-reload

On ajoute la zone comme d'habitude : politique (si besoin est) dans
/etc/opendnssec/kasp.conf et la définition de la zone dans
/etc/opendnssec/zonelist.xml. On reprend tout de l'autre instance. On n'oublie
pas de mettre le fichier de zone non signé à l'emplacement que l'on a indiqué
dans « <Input></Input> ».

On fait prendre en compte l'ajout de la zone :

ods-ksmutil update kasp [uniquement si vous avez modifié kasp.conf]
ods-ksmutil update zonelist


IMPORT DES PAIRES DE CLÉS (KSK ET ZSK) SUR L'INSTANCE DE DESTINATION (A)

On commence par la KSK :

softhsm --import guiguishow.info-ksk.pem --slot 0 --label "<CKA_ID>" --id "<CKA_ID>" --pin <user_pin>

On reprend le même CKA_ID, c'est-à-dire celui que la clé avait sur l'autre
instance. Le pin est toujours l'user pin mais de la nouvelle instance, of
course. 😉

Pour la ZSK, c'est la même commande, seuls l'ID, le label et le fichier source
changent.


ASSOCIATION DES CLÉS (KSK ET ZSK) À LA ZONE SUR L'INSTANCE DE DESTINATION (A)

La documentation se trouve ici : ods-ksmutil - OpenDNSSEC Documentation. Pour
des exemples pratiques (pour comprendre la syntaxe des valeurs à passer aux
différents paramètres, par exemple) : OpenDNSSEC training (page 22).

Import de la KSK :

ods-ksmutil key import --cka_id "<CKA_ID>" --repository <nom_repository> --zone <nom_zone> --bits 2048 --algorithm 8 --keystate ACTIVE --keytype KSK --time <datetime_passage_à_l'état_ACTIVE>

On reprend toujours le même CKA_ID. La valeur du paramètre « --repository » est
le nom donné à votre HSM dans /etc/opendnnsec/conf.xml (« SoftHSM » par défaut).
Les paramètres de la clé (taille, algorithme cryptographique) sont indiqués dans
kasp.conf.

La date et l'heure du passage de cette clé à l'état « active » peut être trouvé
dans la base de données SQLite de l'ancienne instance (B). Non, je n'ai pas
trouvé une manière plus conviviale de faire cela.

# sqlite3 /var/lib/opendnssec/db/kasp.db
sqlite> select HSMkey_id,active from dnsseckeys inner join keypairs on keypairs.id = dnsseckeys.keypair_id;

Comme indiqué dans le PDF d'exemples, le format de la valeur de ce paramètre est
: AAAAMMDDHHMMSS.

Pour la ZSK, il faut suivre la même procédure, seuls « CKA_ID », la taille de la
clé et la datetime de création changent et « --keytype KSK » devient « --keytype
ZSK ».

Évidemment, il est possible de faire la transition d'une instance d'OpenDNSSEC à
une autre alors que les clés sont dans un autre état que « active ». Il faut
alors adapter le paramètre « --keystate ». Je ne recommande pas cela à cause des
timings, toussa.

Maintenant, il faut nettoyer les états associés à la zone. Sans cela, l'auditeur
(ods-auditor) retournera une erreur « Key (xxx) has gone straight to active use
without a prepublished phase » dans les logs qui bloquera le processus de
signature (c'est le principe d'un auditeur en même temps : vérifier que tout est
cohérent avant de signer 😛 ) et ça serait dommage de désactiver l'auditeur pour
si peu.

ods-signer clear <nom_zone>
rm /var/lib/opendnssec/tmp/tracker/<nom_zone>* /var/lib/opendnssec/tmp/<nom_zone>.* /var/lib/opendnssec/signconf/<nom_zone> /var/lib/opendnssec/signed/<nom_zone>

On peut désormais réactiver la génération automatique des paires de clés pour
les zones en re-commentant « <ManualKeyGeneration/> » dans la section « Enforcer
» du fichier /etc/opendnssec/conf.xml.

On fait prendre en compte les changements :

ods-control stop && ods-control start

Maintenant, la commande « ods-ksmutil key list --verbose » doit vous montrer une
KSK et une ZSK pour votre zone avec une datetime de transition identique à
l'ancienne instance (B) et votre zone doit être signée.


DIVERS

Si vous avez mis de mauvaises clés dans le SoftHSM ou de mauvais paramètres dans
OpenDNSSEC, il est possible de les effacer afin de pouvoir recommencer (sinon
les ID identiques empêchent cela) :

# Effacer une clé dans le SoftHSM
ods-hsmutil remove <CKA_ID> 
   OU
pkcs11-tool --module /usr/lib/softhsm/libsofthsm.so -b -d <CKA_ID> -y privkey --login --pin=<USER_PIN> --slot 0
 
# Effacer une clé dans OpenDNSSEC
# sqlite3 /var/lib/opendnssec/db/kasp.db
sqlite> select id from keypairs where HSMKey_id="<CKA_ID"; [notez l'ID]
sqlite> delete from keypairs where id=<ID_noté_ci_dessus>;
sqlite> delete from dnsseckeys where keypair_id=<ID_noté_ci_dessus>;

Note : l'outil pkcs11-tool se trouve dans le package opensc sous Debian. Il
permet également de lister les clés présentes dans un slot (la sortie de cette
commande est complémentaire à celle de la commande « ods-hsmutil list ») :

pkcs11-tool --module /usr/lib/softhsm/libsofthsm.so --list-objects --slot 0 --login --pin=<USER_PIN>

Supprimer une zone (n'affecte pas les clés dans la base de données SQLite
d'OpenDNSSEC) :

ods-ksmutil zone delete -z <nom_zone>


Catégorie: DNS & DNSSEC / Tags: aucun tag / Commentaires fermés sur Basculer une
zone DNS signée d’une instance d’OpenDNSSEC à une autre


COMMENT METTRE EN PLACE UN SERVEUR DNS RÉCURSIF-CACHE OUVERT DANS DE BONNES
CONDITIONS

Posté le 23 août 2014 à 18h34 par GuiGui



Chez ARN, FAI associatif alsacien, on a mis en place un serveur DNS
récursif-cache ouvert il y a un peu moins d'un an. Il y a quelques précautions à
prendre et je n'ai pas trouvé un « how-to » qui ferait le tour de l'essentiel de
la problématique.

Attention : ce billet n'est pas à prendre comme parole d'évangile. Il s'agit
juste d'un retour d'expérience et de quelques notes d'un n00b qui s'est penché
sur le sujet.


TABLE DES MATIÈRES

 * Table des matières
 * Définitions sous-jacentes
 * Pourquoi mettre à disposition un serveur DNS récursif-cache ouvert ?
 * Typologie des attaques
 * Comment procéder ?
   * Adresse mail de contact valide
   * Supervision et métrologie
   * Préparer une configuration fermée
   * Choisir des méthodes pour juguler les attaques
     * RRL
     * Limitation de trafic global en utilisant Netfilter
     * Limitation de trafic portant sur le QTYPE ANY avec Netfilter
     * Limitation de trafic portant sur des QNAME précis avec Netfilter
     * Limiter la taille des réponses que notre récursif-cache fera sur UDP
   * Tester vos contre-mesures
 * Problèmes rencontrés




DÉFINITIONS SOUS-JACENTES

Je n'expliquerai pas le principe des attaques par amplification+réflexion, que
ça soit en utilisant le protocole DNS ou non, mais je vous donne quelques
ressources intéressantes concernant ce sujet :

 * Il est recommandé de fermer les serveurs DNS récursifs ouverts chez Stéphane
   Bortzmeyer.
 * En vidéo, avec un exposé des contre-mesures lors des JRES 2013.
 * Ici même.
 * When the Sky is Falling - Network-Scale Mitigation of High-Volume
   Reflection/Amplification DDoS Attacks (via FRnOG).

Je ne détaillerai pas non plus les directives de configuration pour ouvrir votre
récursif-cache.


POURQUOI METTRE À DISPOSITION UN SERVEUR DNS RÉCURSIF-CACHE OUVERT ?

C'est en effet l'aspect le plus important : si l'on ne le comprend pas, on
arrive à la conclusion qu'un récursif-cache qui répond uniquement aux blocs
d'IPs qui ont été attribués à l'association suffit amplement. Mon avis sur cette
question (liste non ordonnée) :

 * Parce qu'on peut le faire. 🙂
 * Parce que c'est enrichissant techniquement (montée en compétences) de
   chercher comment proposer un récursif-cache ouvert de manière sûre (en
   nuisant le moins possible à autrui).
 * Quelles garanties offrent les FAI et les gros (Google Public DNS, OpenDNS) en
   terme de neutralité des réponses ? Pour les FAI, on a des antécédents pour
   juger sur pièces : pub si réponse inexistante il y a quelques années,
   copwatch-idf, ARJEL, TPB en Belgique, ... La censure via le DNS est à la
   mode. OpenDNS mentait (oui, c'était désactivable, avec un compte mais galère
   si IP dynamique) et ils peuvent recommencer. Nuançons toutefois : les FAI
   associatifs ne sont pas des associations de malfaiteurs et sont soumises au
   même droit que les autres FAI. Ce qui implique de se conformer à une décision
   judiciaire ... quand on est parmi les parties citées à comparaître ... ce qui
   n'est pas le cas actuellement (oui, oui, je sais, le principe d'égalité
   devant la loi). Attention : je ne dis pas que les FAI associatifs sont une
   échappatoire mais simplement que les adhérents seront forcément
   consultés/informés de toute mesure prise qui serait contraire à l'éthique de
   l'association, ce qui est déjà une avancée majeure comparée à rester dans
   l'ignorance avec un fournisseur de récursif DNS sans éthique.
 * Le serveur DNS récursif-cache utilisé, tout comme le FAI, est un point assez
   central dès que l'on parle de vie privée : le FAI voit tout puisqu'il est
   l'intermédiaire obligatoire entre votre réseau et le reste des Internets, le
   récursif-cache voit toutes les requêtes DNS et comme la quasi-totalité des
   communications sur Internet commencent par une requête DNS ... Pour plus
   d'informations, je vous invite à lire DNS privacy considerations. Donc, c'est
   important que des structures qui s'engagent à être correctes au niveau de la
   neutralité proposent des solutions (argument de Julien Vaubourg). Utiliser un
   récursif-cache alternatif à celui de son FAI sans éthique n'empêche pas ce
   dernier de tout voir et de pouvoir altérer, mais c'est un début.
 * Dès qu'il y a un intermédiaire, qu'il soit associatif ou non, on peut avoir
   un doute légitime le concernant. En réaction, on se monte tous un
   récursif-cache validant à la maison sans forward vers un récursif commun ?
   Quid alors de la charge induite sur les serveurs DNS qui font autorité (on ne
   bénéficie plus de mutualisation du cache) ? Est-ce à eux de supporter le coût
   ? On notera au passage la disparité que cela produira entre les gros
   hébergeurs DNS/les TLD, qui pourront absorber le trafic supplémentaire (si
   l'on suit le raisonnement à terme), et les autres, ce qui conduira à une
   concentration des acteurs. Nuançons : oui, les serveurs de noms qui font
   autorité pour guiguishow.info. sont beaucoup, beaucoup moins sollicités que
   ceux qui font autorité sur info. et je n'ai aucun doute que la racine et les
   TLD tiendront le choc. Je pense que chaque réseau (at home, petite grappe de
   serveurs, ...) devrait avoir son récursif-cache validant, local et de
   confiance qui forward simplement les requêtes à des récursifs-cache
   mutualisés de confiance (pour la partie éthique / neutralité des réponses).
   On obtient un effet de strates (comme avec NTP) qui permet de ne pas
   surcharger les serveurs qui font autorité tout en gagnant une validation
   DNSSEC locale donc sûre ainsi qu'en performance.
 * Un récursif-cache neutre et validant, ça ne court par les rues. C'est pour
   cette raison que je pense qu'il est du devoir des FAI associatifs de proposer
   ce type de service. FDN, FAI associatif, propose un récursif neutre mais il
   ne fait pas de validation DNSSEC (on pourrait nuancer l'intérêt de ce point
   avec le problème du dernier kilomètre : la validation doit se faire au plus
   près du demandeur, de l'utilisateur final pour offrir toutes ses garanties),
   DNS-OARC propose un récursif-cache validant mais on n'a aucune garantie sur
   la neutralité des réponses données.
 * Parce qu'il ne doit pas y avoir que les gros (Google, OpenDNS) qui puissent
   le faire sans crainte sous prétexte qu'ils ont le blé/l'image/les
   ressources/les couilles/les ovaires/autre. Liberté d'entreprendre, tout
   simplement. Je veux pouvoir monter un récursif DNS parce que c'est faisable.
   Point. Je veux avoir la possibilité de le faire moi-même ou dans le cadre de
   mon association FAI favorite.
 * Il peut aussi y avoir un besoin d'itinérance. Je ne suis pas toujours
   connecté depuis ma ligne ADSL/mon VPN ARN. Répondre à ce besoin par une
   recommandation d'utiliser un VPN, ça me semble possible en entreprise mais
   décalé en dehors de ce cadre-là. Ça peut aussi constituer une première
   approche de nos idées, de notre cause par un futur adhérent. Un
   récursif-cache ouvert sert aussi pour des "démos" (au sens large) :
   commençons par arrêter de taper dig @8.8.8.8 / echo "nameserver 8.8.8.8" >
   /etc/resolv.conf quand on fait des tests/du debug devant/chez des non inités
   à notre cause et on aura alors plus de crédibilité pour les convaincre
   puisqu'il s'agit là d'un simple effet de prescription "si cet ami dont je
   pense qu'il a un bon niveau technique utilise Google Public DNS, alors ce
   service sera très bien pour moi".
 * Dès que l'on parle de mettre en place un serveur DNS récursif-cache ouvert,
   les yeux des interlocuteurs s'écarquillent. Mais quid des clusters NTP
   ouverts volontairement et surveillés ? Quid des serveurs de jeux vidéos
   (récupérer le statut sur Call of Duty (et d'autres) = UDP = sensible à une
   attaque par réflexion) ? Si l'on doit tout fermer et se la jouer
   individualisme, on ne va pas s'en sortir, à mon humble avis. On notera aussi
   qu'une attaque par réflexion+amplification peut être conduite avec un serveur
   DNS qui fait autorité, particulièrement si ce serveur sert des zones signées
   avec DNSSEC. Doit-on fermer les serveurs qui font autorité ? Quid des
   serveurs SNMP ouverts sans raison chez ces mêmes interlocuteurs ? Je passe
   sur les NTP ouverts par défaut chez Juniper, c'est cadeau.
 * Évidemment, il ne s'agit pas non plus de faire n'importe quoi puisqu'un
   récusif-cache ouvert est complice involontaire de l'attaquant en cela que
   c'est lui qui rend une attaque par réflexion+amplification intéressante
   (dissimulation relative de l'attaquant, amplification). Il y a tout une
   chaîne d'acteurs à protéger au-delà du réseau dans lequel se trouve le
   récursif-cache ouvert : les upstreams qui n'ont pas à assumer le choix,
   plusieurs victimes qui n'ont rien demandé, ... Si le réseau se fait
   blackholer par un opérateur, il sera également impossible pour les
   utilisateurs de ce réseau d'accéder aux services hébergés par cet opérateur
   ou derrière cet opérateur (downstreams). La mise en place de contre-mesures
   lors de la prise de décision de fournir un récursif-cache ouvert est donc une
   obligation morale envers autrui, à mon sens.
 * En conclusion pour ceux qui n'ont pas tout lu : ne pas confondre récursif
   ouvert par erreur/abandonné et récursif ouvert sciemment et surveillé. FDN
   n'a pas succombé à son récursif ouvert car il est surveillé et rate-limité
   (uniquement les requêtes portant sur le QTYPE ANY, à ma connaissance).


TYPOLOGIE DES ATTAQUES

Ce que j'ai observé, sur l'infra d'ARN, en presque un an :

 * Quel est le type de serveur DNS qui est le plus utilisé dans des attaques par
   réflexion+amplification, serveur qui fait autorité ou récursif ? Je n'ai vu
   aucune attaque sur notre serveur qui fait autorité (les requêtes pour
   vérifier s'il est un récursif ouvert ne comptent pas, of course). J'explique
   cela par le fait que nos zones sont trop peu intéressantes (elles ne sont pas
   signées, la requête la plus intéressante, de type ANY, a une taille de 71
   octets au niveau 2 et génère une réponse de 337 octets) et inconnues
   comparées à zones intéressantes "bien connues" comme *.gov, isc.org, ... (à
   partir d'un scan réseau, il est possible de savoir qu'un récursif ouvert est
   adressé par telle IP mais pas de savoir quelles zones sert un serveur DNS qui
   fait autorité adressé par telle IP).
 * Requêtes de type ANY ou non ? Les deux et la proportion semble équivalente/se
   lisser sur une longue période : tantôt une écrasante majorité de requêtes de
   type ANY, tantôt une majorité de requêtes qui utilisent edns (pour pousser la
   limite de la réponse sur UDP au-delà des 512 octets) et qui portent sur de
   gros RRset A/AAAA (et une fois TXT), et aussi les deux en parallèle.
 * Régularité et intensité ? L'intensité est variable. Sans parler de fond
   permanent, il y a quand même quelques tests (es-tu un récursif ouvert ?) et
   plus si affinité (hop, je te fais passer quelques requêtes et je m'arrête) en
   quasi-permanence. Impossible de parler d'attaque à ce stade-là. À côté de
   cela, il y a les pics temporaires : 3/4 IPv4 sources différentes qui émettent
   en continu des requêtes qui génèrent des réponses supérieures à 4 ko, ce qui
   nous donne des pics de l'ordre de 100-140 kbps très régulièrement (de l'ordre
   d'au moins une fois par 24 heures). La durée de ces pics est extrêmement
   variable : plusieurs dizaines de minutes à quelques heures. On constate aussi
   un effet de rafales puis silence puis rafale que je ne m'explique pas dans le
   cadre d'une attaque... Le plus gros pic enregistré était de l'ordre de 350
   kbps sur plusieurs jours. C'était dans les derniers mois de 2013, quand les
   attaques par réflexion+amplification étaient extrêmement à la mode. ÉDIT du
   05/09/2014 à 16h45 : Nouveau pic à 700 kbps, ANY webpanel.sk, environ 4 ko au
   compteur, plusieurs dizaines d'IP sources réparties dans environ 20 /24,
   depuis plus d'une semaine (28 août - encore en cours aujourd'hui). Fin de
   l'édit. Au niveau de la régularité, je n'ai observé aucun schéma sur le long
   terme (pas plus la nuit que le jour (heure de Paris), les périodes de congés
   que les jours ouvrés, ...). Il peut se passer plusieurs jours sans attaque
   puis une déferlante de pics.
 * Domaines connus ou inconnus ? Après coup, je me suis rendu compte que cette
   métrique n'est pas pertinente car subjective (connu de qui ? Quelle portée
   géographique ? Connu selon quelle intensité ?). Je pensais pouvoir établir
   une typologie des domaines utilisés afin de faire de la limitation de trafic
   plus contraignante pour les domaines clairement conçus dans l'objectif de
   servir dans une attaque. Mais ça ne veut rien dire : cela peut-être un
   sous-domaine proposé par un hébergeur low-cost donc le site web donne une
   apparence légitime, cela peut conduire à un site web en langue étrangère
   voire à pas de site web du tout, ... Bref, impossible d'en déduire quoi que
   ce soit et de faire une classification (à partir d'un seul point de collecte,
   j'entends, si un même domaine est vu par plusieurs points de collecte, on
   peut avoir un doute légitime).
 * IPv4 ou IPv6 ? Les attaquants ne sont pas IPv6-ready, très clairement.

Cette typologie vaut ce qu'elle vaut puisque je l'ai réalisée sans méthodologie
ni rigueur scientifique.


COMMENT PROCÉDER ?

Selon moi, il y a quelques étapes à suivre avant de pouvoir ouvrir un récursif
DNS au monde entier l'esprit serein.

ADRESSE MAIL DE CONTACT VALIDE

La première étape est de faire en sorte que l'on puisse vous contacter en cas de
problème. Cela se fait à travers la base de données de votre RIR. Pour le RIPE,
il suffit d'utiliser ce formulaire. En indiquant les adresses IPv4 et IPv6 que
vous allez assigner à votre récursif ouvert, vous devez obtenir une adresse mail
de contact. Évidemment, vous testerez cette adresse mail en vérifiant qu'elle
est fonctionnelle et qu'elle pointe bien vers des personnes qui seront en
capacité d'agir en cas de signalement. Si le formulaire vous retourne rien, vous
avez quelques objets à créer dans la base de données de votre RIR.

SUPERVISION ET MÉTROLOGIE

La deuxième étape est de superviser la machine (physique, virtuelle, LXC, ...)
qui sera votre récursif ouvert, pas tellement pour savoir si le serveur
(logiciel) fonctionne, n'est pas planté, ... mais plutôt pour grapher le débit
et le nombre de paquets sortants. Oui, c'est bien le trafic sortant qui est
intéressant : quelle volumétrie de trafic ce serveur envoie-t-il à l'extérieur ?

L'objectif est triple :

 * Être averti d'une grosse attaque. L'outil de supervision doit lever une
   alerte, soit quand un seuil plutôt large est atteint sur une période très
   courte, de l'ordre de la minute (un pic important quoi), soit quand un seuil
   plutôt faible est atteint sur une période d'échantillonnage plus longue, de
   l'ordre des 5 minutes. Ma préférence va pour le deuxième type de
   seuil/échantillonnage car il indique qu'une volumétrie de trafic inhabituelle
   s'écoule depuis quand même une certaine période, ça serait bien d'aller y
   jeter un œil. Pour vous donner un ordre d'idée, chez ARN nous faisons un
   échantillonnage par 5 minutes et une alerte dès 250 kbps (1/4 de mbps).
 * Garder un historique grâce à la métrologie. À la fois pour avoir des éléments
   de réponse pour répondre aux mails d'abus alors que pourtant vous n'avez reçu
   aucune alerte (le cas s'est produit chez ARN, la victime a simplement envoyé
   un mail à tous les responsables des serveurs DNS récursifs qui l'attaquaient
   sans se préoccuper du débit effectif émis par chacun des récursifs) et pour
   avoir une trace visuelle, toujours plus expressive que des chiffres.
 * ÉDIT du 04/09/2014 à 19h00 : Calculer et grapher automatiquement le 95e
   centile. Très utile pour apprécier la facturation de vos transitaires. Vous
   pouvez alors raisonner en terme de coût : combien l'attaque en cours
   va-t-elle coûter et décider alors de fermer votre récursif-cache
   temporairement ou définitivement. Fin de l'édit

Cela peut se faire simplement avec votre outil de supervision/métrologie favori,
Zabbix dans le cas d'ARN.

Ça peut aller jusqu'à utiliser Netflow/IPFIX ou des outils plus centrés sur le
DNS comme DSC (chiffres, graphes, par QTYPE, remonter les QNAME populaires,
...).

On peut aussi créer des règles iptables "de comptabilité" : règles en « -j
ACCEPT » qui permettent de comptabiliser (iptables -L -n -v pour voir les
compteurs) les paquets entrants et sortants du port udp/53 de votre récursif.

Chez ARN, on s'est arrêté à Zabbix + compteurs iptables pour la prod'.

PRÉPARER UNE CONFIGURATION FERMÉE

Dans la configuration de votre serveur DNS, prévoyez, en commentaire, le morceau
de configuration qui ferme le récursif à votre réseau. L'idée est qu'en cas
d'une sévère attaque, alors que vous serez totalement paniqués, vous puissiez
facilement fermer votre récursif en attendant que ça se passe.

Cela a encore plus d'intérêt quand vous avez un moyen facile et permanent
d'accéder à une console sur vos machines même si vos liens réseaux vers
l'extérieur (transit, peering) sont saturés : accès physique ou accès distant
(via IPMI en OOB, par exemple). Chez ARN, nous avons un accès IPMI à nos
machines, pour information.

CHOISIR DES MÉTHODES POUR JUGULER LES ATTAQUES

RRL

Response Rate Limiting consiste à limiter le nombre de réponses par seconde que
fournit un serveur DNS qui fait autorité à un préfixe IP(v4/v6) donné. C'est
implémenté dans tous les logiciels serveur DNS qui font autorité : BIND >= 9.9.4
(pas activé à la compilation par défaut, 9.10 pour que ça soit le cas), nsd >=
3.2.15, knot, ...

Les avantages :

 * On est à un niveau très fin : quel couple QTYPE+QNAME dépasse le seuil défini
   ? Seuls les préfixes IP desquels émanent des requêtes portant sur ce couple
   seront rate-limitées. RRL s'adapte à l'attaque en cours, sans aucun travail
   humain puisque l'identification des paramètres de l'attaque (QNAME, QTYPE,
   sources) est automatique.
 * Une fois le seuil atteint, le serveur répondra quand même des réponses
   tronquées (un SLIP) invitant un vrai client DNS à retenter en TCP. Une
   réponse tronquée étant d'une taille inférieure, on annule l'effet
   d'amplification. Un client légitime dans un préfixe rate-limité aura quand
   même une réponse et ne sera pas totalement pénalisé.

Les inconvénients :

 * Les versions des logiciels serveur DNS qui implémentent RRL ne sont pas
   encore dans les dépôts stable de Debian. Pour BIND, la version 9.9.5 présente
   dans wheezy-backports a été compilé avec la fonctionnalité RRL. Rappel : la
   team Debian-security ne s'occupe pas des backports. 😉
 * On promène les paquets (requêtes) dans notre réseau pour finalement que le
   serveur refuse d'y répondre. Nuançons : ce n'est pas couteux puisque c'est en
   interne de notre réseau et que c'est les réponses qui ont un impact.
 * RRL est-il adapté pour les récursifs-cache ? Un récursif-cache n'a pas à
   interroger un serveur qui fait autorité des dizaines de fois par seconde pour
   un même QTYPE+QNAME grâce à son cache, ce qui justifie l'emploi de RRL sur
   les serveurs faisant autorité. Le client d'un récursif-cache en revanche n'a
   pas de cache donc il peut légitimement interroger le récursif-cache des
   dizaines de fois par seconde pour un même couple QTYPE+QNAME. Mon avis, basé
   sur les autres formes de limitation de trafic est qu'il suffit d'adapter le
   seuil. Mais peut-être que je me trompe sur ce point.

Chez ARN, cette solution n'a pas été retenue du fait qu'elle n'est pas
implémentée dans les versions de logiciels serveur DNS disponibles dans les
dépôts stable de Debian.

LIMITATION DE TRAFIC GLOBAL EN UTILISANT NETFILTER

Puisque le routeur d'entrée d'ARN est une machine GNU/Linux (oui, un routeur ce
n'est pas forcément un Cisco très cher 😉 ), on peut utiliser Netfilter pour
limiter le trafic à destination de notre récursif-cache sur le port udp/53.

Pour la mise en pratique (pour le choix du module hashlimit, voir : Limiter le
trafic d'un serveur DNS (notamment d'un récursif ouvert)) :

#IPv4
iptables -A FORWARD -o eth1.140 ! -s 89.234.141.0/24 -d 89.234.141.66/32 -p udp -m udp --dport 53 -j DNS-RATE-LIMIT
iptables -A DNS-RATE-LIMIT -m hashlimit --hashlimit-above 10/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name RL-DNS-GLOBL-v4 --hashlimit-srcmask 24 -m comment --comment "RATE-LIMIT ALL DNS QUERIES 10/s burst 20" -j DROP
 
#IPv6
ip6tables -A FORWARD -o eth1.140 ! -s 2a00:5881:8100::/40 -d 2a00:5881:8100:1000::3/128 -p udp -m udp --dport 53 -j DNS-RATE-LIMIT
ip6tables -A DNS-RATE-LIMIT -m hashlimit --hashlimit-above 10/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name RL-DNS-GLOBL-v6 --hashlimit-srcmask 56 -m comment --comment "RATE-LIMIT ALL DNS QUERIES 10/s burst 20" -j DROP

La création d'une chaîne nommée « DNS-RATE-LIMIT » vous semblera légitime dans
la section suivante.

Ici, on autorise 10 requêtes DNS par seconde par /24 et par /56 avec un burst à
20 requêtes par seconde. Le burst signifie que le client a le droit à 20
requêtes dès la première seconde puis 10 requêtes par seconde pour les secondes
suivantes. S'il n'atteint pas le seuil (10 requêtes par seconde donc), il
récupère la possibilité d'atteindre 20 requêtes par seconde au bout de 2
secondes (combien de secondes faut-il pour atteindre 20 quand on en autorise 10
requêtes par seconde ?). Le contenu des hashtables sont consultables depuis
/proc/net/ip*t_hashlimit/.

En fonction de l'organisation de votre infra, il est inutile de limiter le
trafic émis par l'infra elle-même et les abonnés (VPS/VPN/ADSL) si vous avez
déployé des contre-mesures pour lutter contre l'usurpation d'IP (BCP 38 + drop
des paquets qui ont une de vos IPs en source en entrée de votre réseau). De
plus, un FAI associatif a vocation à rester à taille humaine : on se connaît, on
se fait confiance (et des hébergeurs low-cost bien connus sont plus pratiques et
moins chers pour mener à bien une attaque). De plus, le récursif étant en local,
les requêtes peuvent s'enchaîner plus vite donc le seuil peut-être atteint plus
facilement. Exemples chez ARN : OpenVPN et son mécanisme d'iroute empêchent
l'usurpation d'IP sur la partie VPN. Un VPS ne peut pas usurper une IP (qu'elle
soit interne ou externe) car on a déployé BCP 38, Ingress Access Lists pour être
précis, avec iptables, sur chaque interface réseau virtuelle.

On se rend compte que cette méthode impose un dilemme moral puisque plus on est
permissif pour les usages légitimes, plus on est permissif envers les
attaquants. J'ai choisi les seuils (10 r/s burst à 20) en fonction des exemples
illustrant RRL ainsi qu'en fonction des exemples donnés par Stéphane Bortzmeyer
(voir les ressources pointées au sommet de ce billet) puis j'ai ajusté. D'après
mes tests, on ne peut pas descendre en dessous de ces valeurs sous peine de
nuire à des usages légitimes : une installation Debian classique nous fait un
pic à 12 r/s pendant l'installation (si la résolution échoue, l'utilisateur
obtient une erreur et ne peut continuer), résolution des reverses dans un
logiciel torrent, page web bien chargée sans utilisation
d'Adblock/NoScript/autre, ...

Exemple récent de ce que permettent ces seuils dans la théorie : la requête ANY
nrc.gov génère une réponse de 4,278 ko soit 34,224 kb. On considère 4 IP source
différentes (cf typologie) dans 4 préfixes /24 différents en simultané : 136,896
kb. Chaque IP a le droit à 10 r/s en vitesse de croisière : 1368,96 kbps soit
1,33 Mbps. On est au niveau applicatif, il faut donc ajouter les entêtes IP+UDP
(ce qui rendra le facteur d'amplification moins impressionnant mais on n'est pas
la pour ça). Est-il moralement acceptable de laisser filer potentiellement plus
de 1,33 Mbps de trafic pourri ? D'autant plus que les attaquants n'envoient pas
un nombre constant de paquets mais agissent plutôt en mode grosse rafale, moins
de paquets, grosse rafale, etc. Donc les 20 r/s du burst se débloquent assez
régulièrement, ce qui permet donc à la grosse rafale de passer.

Le seul avantage que je vois à cette solution est, qu'une fois le seuil dépassé,
les paquets en surplus provenant de préfixes limités sont supprimés en entrée du
réseau.

Les inconvénients :

 * La limitation porte sur un préfixe (/24 en IPv4, /56 en IPv6). Il est évident
   que l'on joue sur la dispersion des utilisateurs de notre récursif dans des
   préfixes différents : si plusieurs utilisateurs viennent du même préfixe avec
   des usages "gourmands" sur une même période de temps, alors des usages
   légitimes seront bloqués avec les seuils présentés ci-dessus, c'est une
   certitude. Et un seuil plus permissif, même uniquement un burst plus élevé,
   permettra aux attaquants de générer encore plus de trafic pourri. Tout est
   histoire de compromis en sécurité informatique.
 * J'ai remarqué que les limitations présentées ci-dessus sont globalement
   inefficaces. Les règles iptables ne sont pas souvent déclenchées (un peu
   moins d'une centaine par semaine) car le nombre de paquets par seconde ne
   dépasse pas le seuil défini et car le burst se régénère vite (les deux sont
   liés). Notamment parce que des attaquants subtils utilisent plutôt un plus
   grand nombre de récursifs-cache couplé à un petit de requêtes par seconde
   destinées à chaque récursif-cache que l'inverse. J'en arrive à la conclusion
   que ces limitations protègent de gros chocs mais sont trop perméables aux
   attaques au quotidien.

Chez ARN, cette solution a été retenue mais elle ne suffit pas : on identifie
assez clairement le besoin de limiter plus fermement certains QTYPE et QNAME.

LIMITATION DE TRAFIC PORTANT SUR LE QTYPE ANY AVEC NETFILTER

Une partie des attaques utilisent le QTYPE ANY. Ce type d'enregistrement est
valide (au sens des normes donc on doit le laisser passer) mais sert très
rarement dans la pratique sauf debug et logiciels plutôt mal conçus et désuets.
On peut envisager de limiter plus fortement le trafic des requêtes DNS portant
sur ce type.

La difficulté vient du fait que, dans le format d'un paquet DNS, le QTYPE arrive
après le QNAME. On est donc dépendant de la taille du QNAME pour trouver le
QTYPE dans le paquet. Il est donc impossible de limiter toutes les requêtes de
type ANY en utilisant un langage tel que u32. On peut toutefois utiliser le
module « string » de Netfilter qui fait une recherche linéaire.

Pour la mise en pratique (en complément de la section précédente, d'où la chaîne
« DNS-RATE-LIMIT » 😉 ) :

#IPv4
iptables -I DNS-RATE-LIMIT -m string --algo bm --hex-string "|00 00 ff 00 01|" --from 28 -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS-ANY-v4 --hashlimit-srcmask 24 -m comment --comment "RATE-LIMIT DNS ANY QTYPE 1/s burst 2" -j DROP
 
# IPv6
ip6tables -I DNS-RATE-LIMIT -m string --algo bm --hex-string "|00 00 ff 00 01|" --from 48 -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS-ANY-v6 --hashlimit-srcmask 56 -m comment --comment "RATE-LIMIT DNS ANY QTYPE 1/s burst 2" -j DROP

Ici, on autorise 1 requête de type ANY par seconde par /24 et par /56 avec un
burst à 2 requêtes par secondes.

Explications :

 * Concernant le motif recherché, « 00 00 ff 00 01 » : 00 : fin du QNAME,
   c'est-à-dire « . », la racine ; 00 ff : QTYPE, codé sur 2 octets (16 bits),
   00 ff = 255 = ANY ; 00 01 : CLASS, codé sur 2 octets (16 bits), 1 = IN. Pour
   les numéros correspondant à chaque QTYPE/CLASS/autre, voir : Domain Name
   System (DNS) Parameters - IANA 😉 . On peut utiliser un motif plus court mais
   il faut alors faire attention aux faux positifs.
 * Concernant le début de la recherche dans un paquet, « --from 28/48 » : étant
   donné que ce module est plus gourmand que u32 (par exemple) car recherche
   linéaire et que le motif peut conduire à des faux positifs, je trouve que
   c'est une bonne idée de commencer la recherche au niveau applicatif, sans se
   soucier des couches inférieures. On prend la taille standard, sans s'occuper
   des options IP (v4 comme v6). Exemple : 20 octets IPv4 + 8 octets UDP. Le
   module string compte à partir de 0 (cf man) donc --from 28 : commence
   l'analyse au 29e octet donc au début de DNS. Le module string commence sa
   recherche au début de la couche IP, il ne faut donc pas comptabiliser la
   couche 2 (exemple : ne pas ajouter 14 octets pour Ethernet) ! Sur plusieurs
   sites web, j'ai vu l'usage de « --to » pour se prémunir contre d'immenses
   paquets qui rendraient la recherche très fastidieuse. C'est une mauvaise idée
   à mon avis : on ne peut pas prévoir l'emplacement du QTYPE ! Et si un paquet
   inclut des options IPv4 ou des entêtes IPv6 d'extension ? Et si le QNAME est
   très long ? Le QTYPE sera au-delà de la zone de recherche et le paquet
   échappera donc à notre filtre.
 * Attention à choisir des noms de hashtable différents en fonction de l'usage
   (rate-limit global ou rate-limit ANY). Utiliser une même table dans plusieurs
   règles fait que c'est la limite la plus basse qui sera appliquée MÊME si la
   règle correspondante n'est pas déclenchée ! Exemple : soit le jeu de règles
   de filtrage suivant (sans cumul avec les filtres présentés ci-dessus) :
   
   -A DNS-RATE-LIMIT -m u32 --u32 "0x0>>0x16&0x3c@0x14&0xffffff00=0xff00" -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS --hashlimit-srcmask 24 -m comment --comment "RATE-LIMIT ANY ." -j DROP
   -A DNS-RATE-LIMIT -m u32 --u32 "0x0>>0x16&0x3c@0x14&0xffdfdfdf=0x3495343&&0x0>>0x16&0x3c@0x18&0xffdfdfdf=0x34f5247&&0x0>>0x16&0x3c@0x1c&0xffffff00=0xff00" -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS --hashlimit-srcmask 24 -m comment --comment "RATE-LIMIT ANY isc.org" -j DROP
   -A DNS-RATE-LIMIT -m hashlimit --hashlimit-above 10/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name RL-DNS --hashlimit-srcmask 24 -m comment --comment "RATE-LIMIT ALL 10/s-20/s" -j DROP
   
   Les compteurs (iptables -L -n -v) des deux premières règles n'étaient pas
   incrémentés car les règles n'étaient pas déclenchées car les requêtes étaient
   de type A. Bizarrement, la dernière règle se déclenchait alors qu'une capture
   réseau montrait qu'on avait 4-8 requêtes/seconde mais jamais plus en entrée.
   En sortie de Netfilter, on voyait 1 à 2 requêtes par seconde. Vider les
   règles iptables et les remettre n'avait aucun effet. Après debug, le simple
   fait d'introduire l'une des deux premières règles faisait dysfonctionner la
   dernière règle. Utiliser les mêmes règles mais avec des noms de tables
   différents a résolu ce problème que je n'explique pas.

L'avantage est que ces limitations, complémentaire aux limitations "globales"
sont efficaces : déclenchées beaucoup plus souvent (un peu plus de 8 millions de
paquets en une semaine) sans pour autant empêcher les usages légitimes.

Les inconvénients :

 * Quid des faux positifs que peut provoquer le motif recherché ? Le risque est
   très limité puisque ces recherches s'appliquent uniquement sur la charge
   utile DNS des paquets à destination du port udp/53 de notre récursif. FDN n'a
   pas rencontré de problèmes, à ma connaissance.
 * Une recherche linéaire permet-elle d'encaisser de grosses attaques ou le
   netfilter sur notre routeur d'entrée va devenir un goulot d'étranglement ? Je
   n'ai pas réussi à mettre en avant quoi que ce soit avec mes tests dans un
   lab' local (100 mbps). Peut-être que je m'y suis mal pris.
 * Ces limitations apportent une solution à une partie du problème seulement :
   quid des attaques qui portent sur un gros RRset de type autre que ANY ?

Chez ARN, cette solution a été retenue, en complément d'une limitation globale
du nombre de requêtes par seconde et apporte de bons résultats.

LIMITATION DE TRAFIC PORTANT SUR DES QNAME PRÉCIS AVEC NETFILTER

On peut être tenté de limiter plus fortement le trafic des requêtes portant sur
des QNAME clairement identifiés comme servant dans des attaques par
réflexion+amplification. La première question est de savoir comment on identifie
les QNAME en question. Stats avec DSC ? Un dump réseau (quid alors de la vie
privée des vrais utilisateurs (oui, avec un petit nombre d'abonnés, on peut se
souvenir, de tête, à quel abonné on a donné quelle IP et donc voir des choses
qui ne nous regardent pas)) ? Se baser sur des sites web comme DNS Amplification
Attacks Observer ou Honeypot DNS and amplification attacks ?

Pour la mise en pratique, on utilise les modules u32 et hashlimit de Netfilter.

L'avantage est que cette méthode est très efficace, surtout quand vous ajoutez
préventivement les QNAME que vous trouvez sur les sites web sus-cités.

Les inconvénients :

 * Quelle confiance accorder aux sites web qui répertorient les attaques ?
   Nuançons : on peut très bien construire nos propres stats avec DSC.
 * Comment entretenir le jeu de règles ? D'un côté, trop de règles ralentissent
   Netfilter, de l'autre des règles cessent d'être utiles voire ne le sont
   jamais (toutes les attaques recensées sur les sites web sus-cités n'arrivent
   pas jusqu'à notre récursif). Comment purger les règles automatiquement ?
   Quelle fréquence ? Quels critères ? Quid des QNAME qui cessent d'être
   utilisés temporairement et reviennent en force des mois plus tard (exemple :
   fkfkfkfa.com) ? Bref, l'entretien est loin d'être simple.
 * Le suivi des nouvelles attaques, la création/l'application des règles u32 et
   l'entretien du jeu de règles ont un coût humain qui ne semble pas compatible
   avec l'associatif : le temps humain est précieux, aucune motivation pour
   faire ce boulot, ...

Chez ARN, j'ai longuement testé (et apprécié) cette méthode avant de me rendre
compte que ce n'était pas compatible avec le rythme associatif et de laisser
tomber.

LIMITER LA TAILLE DES RÉPONSES QUE NOTRE RÉCURSIF-CACHE FERA SUR UDP

Avec l'extension edns0, un client DNS a la possibilité d'indiquer à un serveur
DNS qu'il veut recevoir une réponse plus large plus que les 512 octets par
défaut sur UDP. Le serveur peut ainsi s'adapter. Le serveur possède également
une directive de configuration pour indiquer quelle est la taille maximale d'une
réponse qu'il acceptera d'envoyer sur UDP, quelle que soit la valeur indiquée
par le client dans sa requête. Pour BIND et Unbound (à partir de la version
1.4.21), il s'agit de « max-udp-size [1024-4096] » avec une valeur par défaut et
max impératif fixés à 4096 octets. ÉDIT du 04/09/2014 à 18h45 : Unbound n'impose
pas de minimum, contrairement à BIND. Fin de l'édit

Pourquoi ne pas utiliser ces directives de configuration pour limiter les
attaques qui utilisent de gros RRset d'un type autre que ANY et edns ? Ainsi le
facteur d'amplification est réduit et notre récursif-cache intéressera beaucoup
moins les attaquants.

ÉDIT du 05/09/2014 à 17h30 : Si le client de notre récursif-cache est un
stub-resolver (« un résolveur qui ne sait pas suivre les renvois et qui dépend
donc d'un ou de plusieurs résolveurs complets pour faire son travail [...] C'est
ce résolveur minimum qu'appelent les applications lorsqu'elles font un
getaddrinfo() ou getnameinfo(). Sur Unix, le résolveur minimum fait en général
partie de la libc et trouve l'adresse du ou des résolveurs complets dans
/etc/resolv.conf » ), alors il ne fait pas de validation DNSSEC donc il ne
positionne pas le bit DO et donc notre récursif ne lui enverra pas les
signatures cryptographiques (qui sont quand même ce qui fait exploser la taille
des réponses loin devant les IDN et IPv6). En conséquence, les réponses seront
petites. S'il s'agit d'un récursif-cache qui forward les requêtes à notre
récursif (et à d'autres, ce qui permet de switcher sans dommage pour
l'utilisateur final si notre limite est trop basse et impose un passage à TCP
pour une requête donnée), alors une limite de la taille des réponses plus petite
que celle par défaut impactera possiblement uniquement la première résolution
(d'un même nom) d'un client de ce récursif-cache. Les résolutions suivantes de
ce nom seront immédiates puisque mises en cache.

De plus, avant d'être obligé de tronquer sa réponse, un récursif-cache peut
"produire" une section additionnelle minimaliste ce qui a pour effet de réduire
la taille de la réponse, de l'amener en dessous de la limite et donc de fournir
une réponse non tronquée au client (la section « ANSWER » de la réponse est
intacte).

Face à ces optimisations, la taille maximale des réponses par défaut semble
démesurée.

Un usage plus important de TC + passage en TCP ne sera pas toujours pénalisant :
la norme autorise l'utilisation de connexions TCP persistantes. Les
récursifs-cache implémentent cela. Malheureusement, aucun stub-resolver ne
supporte cela à l'heure actuelle.

La question qui reste en suspens pour ma part est : comment mesure-t-on si notre
limite est trop basse et gêne les utilisateurs de notre récursif ? Mesurer la
proportion de trafic TCP versus UDP ? Et si le client (stub-resolver ou récursif
qui forward) n'a pas réessayé suite à l'envoi d'une réponse tronquée mais a
contacté le prochain récursif-cache dans sa configuration ? Un récursif-cache
qui envoi uniquement des réponses tronquées (ce qui est loin d'être le cas avec
une limite à 1460 octets à l'heure actuelle) est un récursif-cache plutôt
inutile, à mon avis. Fin de l'édit.

À titre personnel, je ne vois aucun avantage à cette méthode. ÉDIT du 05/09/2014
à 17h10 : Après avoir examiné à nouveau cette piste, je vois plusieurs avantages
:

 * Ça permet de couper net dans le tas. Illustration avec l'attaque "populaire"
   (du point de vue du récursif d'ARN) du moment : ANY webpanel.sk, environ 4 ko
   au compteur, plusieurs dizaines d'IP source réparties dans environ 20 * /24
   différents. En laissant la limite par défaut (4096 octets) : 700 kbps en
   sortie de notre récursif au 95e centile sur une période de 7 jours. En
   passant la limite à 1460 octets : 180 kbps au 95e centile sur les 39h
   écoulées depuis la reconfiguration. Évidement, cela vient en sus de
   l'utilisation de Netfilter pour limiter le nombre de requêtes par seconde
   portant sur le QTYPE ANY.
 * Cette technique est la seule (pour l'instant, RRL permet aussi cela) à
   pouvoir contrer les attaques de type edns0 + gros RRset de manière
   automatisée puisque nous avons vus ci-dessous que les autres méthodes sont
   soit inefficaces (rate-limiting global) soit manuelles (rate-limiting sur des
   QNAME précis).

Fin de l'édit.

Les inconvénients :

 * On pénalise tout le monde (alors que la limitation de trafic ne s'applique
   qu'à certains préfixes), tout le temps (alors que la limitation de trafic
   s'applique temporairement et uniquement en cas d'abus), pour tous les usages
   (ici même une réponse légitime signée avec DNSSEC pourra être tronquée).
   Certes, un client DNS légitime réessayera en TCP mais on ralentit fortement
   les usages.
 * Quelle est la taille idéale à autoriser ? Celle qui ne pénalise pas les
   usages ? Comment l'identifie-t-on sans être intrusif ni dépendre de notre
   typologie d'utilisateur ? +/- la MTU pour éviter l'overhead causé par la
   fragmentation en cas d'attaque ? Quelle est la taille d'une réponse DNSSEC
   standard ? Qu'est-ce qu'une réponse signée avec DNSSEC standard ? Cette
   limite peut évoluer avec le temps/la population d'utilisateurs, il faut donc
   prévoir de l'adapter.

Chez ARN, cette idée n'a pas dépassé le stade du test dans un lab'. ÉDIT du
05/09/2014 à 17h05 : Une limitation de la taille des réponses sur UDP à 1460
octets est en test depuis le 04/09/2014. Fin de l'édit. ÉDIT du 04/11/2014 à
11h00 : Avec un recul de deux mois : ça juste marche. Les usages légitimes ne
semblent pas être pénalisés et les attaques de forte amplitude ont cessé (on est
à quelques kbps au 95e centile sur un mois). Peut-être les attaquants mesurent
le gain d'amplification obtenu et observent que notre récursif-cache est un
mauvais élève de ce point de vue. Il convient de rester prudent pendant encore
quelques mois : les attaques par réflexion+amplification vont et viennent en
terme de popularité donc il ne faut pas crier victoire trop vite. Fin de l'édit.

ÉDIT du 04/09/2014 à 22h00 : On peut aller encore plus loin et ouvrir un
récursif-cache sur l'extérieur uniquement en TCP. Malheureusement, c'est encore
du domaine du futur et ce, pour plusieurs raisons :

 * Les stub-resolvers (la glibc, utilisée, entre autres, par Debian, en tous
   cas), n'utilisent pas spontanément TCP mais tentent d'abord de faire leur
   requête sur UDP puis, en cas d'obtention d'une réponse tronquée seulement,
   retentent sur TCP. Il n'y a aucune directive de configuration à indiquer dans
   resolv.conf/host.conf pour forcer ce cas d'usage. Étant donné qu'un
   récursif-cache a vocation à avoir une majorité de stub-resolvers comme
   clients, la solution d'un récursif-cache répondant uniquement sur TCP n'est
   pas envisageable à l'heure actuelle. ÉDIT du 22/02/2015 à 13h55 : Depuis sa
   version 2.14, la glibc dispose de l'option « use_vc » (à utiliser dans
   resolv.conf, « options use_vc »). Cette option est disponible depuis Debian
   Jessie. OpenBSD a l'équivalent « tcp ». Les autres implémentations (FreeBSD,
   NetBSD, DragonFlyBSD, bionic (Android, Firefox OS), libresolv (Mac OS X),
   uclibc) ne disposent pas encore d'une telle option, ce qui en limite
   l'impact/l'intérêt. Source : Recursive DNS over TLS over TCP 443. Fin de
   l'édit.
 * Les utilisateurs de notre récursif-cache peuvent être dans des réseaux nazis
   dans lequels les administrateurs croient encore que DNS c'est uniquement
   udp/53 et bloquent donc le port tcp/53 (volontairement avec un pare-feu ou
   involontairement en utilisant des middleboxes mal-conçues). Ces réseaux ne
   sont pas rares ! Même sans évoquer notre cas d'usage, ces configurations
   poseront problèmes de toute façon et disparaîtront à terme.
 * TCP est plus lent (en cas d'absence de support des connexions TCP
   persistantes) et plus coûteux en ressources côté récursif-cache. Lire : Le
   DNS va t-il utiliser de plus en plus souvent TCP ?.

Fin de l'édit

TESTER VOS CONTRE-MESURES

Je n'ai pas été cherché bien loin les outils que j'ai utilisés.

Dans le lab' :

 * Queryperf ;
 * Scapy avec ce genre de script.

Sur la prod' :

 * Une bête boucle shell :
   
   for i in {1..<à adapter en fonction du seuil de la règle iptables à tester>}; do dig @<serveur v4 et v6> +short +retry=0 +time=1 ANY example.net.; [date;] done
   
   « time » avec une valeur d'une seconde permet de voir clairement le
   déclenchement d'une règle iptables. Cette simple boucle permet de vérifier
   que la limitation s'applique sans pour autant bourriner. Je trouve le
   résultat particulièrement lisible : burst puis vitesse de croisière. ÉDIT du
   04/09/2014 à 21h15 : Je n'utilise pas « repeat » pour illustrer cet article
   car je suis un faible qui utilise bash, donc je n'ai pas cette commande
   pourtant built-in dans d'autres shells. Fin de l'édit

 * Une fois la vérification de l'efficacité de vos règles iptables effectuée, il
   vous faudra des beta testeurs pour tester en conditions réelles/normales que
   la limitation ne provoque pas de faux positifs.


PROBLÈMES RENCONTRÉS

 * J'ai constaté un manque flagrant de documentation sur « comment monter un
   serveur DNS récursif-cache ouvert mais surveillé ». Même ceux qui le font,
   comme DNS-OARC ne sont pas bavards à ce sujet. Effet de dissuasion pour
   éviter les mauvaises manipulations et les nuisibles ? Idem, j'aimerais bien
   avoir des feedbacks sérieux sur quelle volumétrie de trafic "pourri" il est
   moralement acceptable de laisser filer sur les Internets.
 * Mettre en place un serveur DNS récursif-cache demande de la patience.
   Simplement car il faut du temps pour tâter le terrain, trouver les bonnes
   méthodes pour tenter de juguler les attaques, ajuster les paramètres du
   rate-limiting, obtenir des feedbacks, ... C'est un travail de longue haleine.
 * L'obtention de feedbacks est elle-même compliquée. D'abord car il est parfois
   difficile d'établir un lien de causalité entre un problème constaté et les
   mesures de limitation du trafic prises (un « could not resolve ... » est
   parlant mais ce n'est pas toujours ce type de message que l'on rencontre).
   Ensuite car les gens ne signalent pas forcément qu'ils rencontrent un
   problème avec le récursif (« c'est peut-être un problème temporaire ?
   problème de réseau ? »). En sont-ils simplement conscients ? Plusieurs
   entrées dans le fichier /etc/resolv.conf ou l'utilisation d'un serveur DNS
   forwarder en local suffisent à masquer le problème (basculement sur d'autres
   serveurs récursifs, cache, ...). Bref, prêtez attention à la configuration
   des machines de vos testeurs.

Merci à Stéphane Bortzmeyer pour sa relecture attentive, mais cela ne veut pas
dire qu'il est d'accord avec tout (notamment sur mon absence d'intérêt pour une
réduction de la taille max des réponses sur UDP).


Catégorie: DNS & DNSSEC, Sécurité / Tags: aucun tag / Commentaires fermés sur
Comment mettre en place un serveur DNS récursif-cache ouvert dans de bonnes
conditions


MA PREMIÈRE (VRAIE) CLÉ PGP

Posté le 17 juillet 2014 à 23h36 par GuiGui



Je me suis sérieusement mis à OpenPGP. C'était dans ma TODO depuis trop
longtemps. Ce billet regroupe juste mes réflexions, ma manière de faire et les
différentes lignes de commandes extraites du man qui pourront m'être utiles un
jour. Rien d'innovant en soi.

Ce billet devait être un shaarli à l'origine mais vu sa longueur, il a atterri
ici.

Attention : ce billet n'est ni de la vulgarisation ni une source d'information
100 % fiable. Il s'agit juste d'un retour d'expérience et de quelques notes d'un
n00b qui s'est penché sur le sujet.

Voici la documentation que j'ai utilisée :

 * Ma nouvelle clé PGP chez Stéphane Bortzmeyer.
 * Creating the perfect GPG keypair chez Alex Cabal.
 * OpenPGP Best Practices.
 * Les subkeys OpenPGP.


TABLE DES MATIÈRES

 * Table des matières
 * Introduction
 * Générer une paire de clés
   * Configurer GnuPG
     * GPG version 1.X ou GPG version 2.X ?
     * Configuration commune à GPG version 1.X et GPG version 2.X
   * Réellement générer votre paire de clés
 * Chiffrer/déchiffrer/signer/vérifier la signature (d')un fichier
 * Stocker vos mots de passe
 * Trouver la clé publique d'un correspondant, la vérifier et l'ajouter à votre
   trousseau
 * Chiffrer/déchiffrer/signer/vérifier la signature (d')un mail
   * Quelques précautions à prendre lors de l'envoi d'un mail signé/chiffré
   * Quid des webmails ?
 * OpenPGP et confidentialité persistante (PFS - Perfect Forward Secrecy)
 * Changer la date d'expiration d'une clé
   * En ligne de commande
   * Avec Enigmail
 * Révocation
   * Générer une nouvelle paire de clés
   * Tester la nouvelle paire de clés
   * Révoquer l'ancienne clé
   * Révoquer une paire de clés avec un certificat de révocation
 * Conclusion




INTRODUCTION

D'abord, il faut faire la différence entre OpenPGP (la norme, RFC 4880) et les
différentes implémentations disponibles (PGP, GnuPG, GPG4Win, ...).

ÉDIT du 30/05/2016 à 16h00 : Dans ce billet de blog, je vais traiter
exclusivement de GnuPG (+ Enigmail comme frontend) c'est-à-dire l'implémentation
disponible sous GNU/Linux. Pour les utilisateurs-trices de Windows, je vous
renvoie vers le tuto de Zythom (partie 1, partie 2 et partie 3) d'une part et
vers les explications de Numérama d'autre part. Je vous rappelle néanmoins qu'il
ne peut pas y avoir de sécurité sur un système fermé, c'est-à-dire un système
dont personne (sauf Microsoft) n'a le code source et ne sait donc comment il
fonctionne. Le logiciel libre apporte des garanties supplémentaires nécessaires
(mais pas suffisantes, mais c'est toujours mieux). Fin de l'édit.

Ensuite, il faut assimiler qu'on ne désigne pas une clé par son ID (identifiant)
qu'il soit court ou long mais par son empreinte (fingerprint), pour des raisons
de sécurité : « Short OpenPGP Key IDs, for example 0×2861A790, are 32 bits long.
They have been shown to be easily spoofed by another key with the same Key ID.
Long OpenPGP Key IDs (for example 0xA1E6148633874A3D) are 64 bits long. They are
trivially collidable, which is also a potentially serious problem. If you want
to deal with a cryptographically-strong identifier for a key, you should use the
full fingerprint. You should never rely on the short, or even long, Key ID. ».
Source : OpenPGP Best Practices.


GÉNÉRER UNE PAIRE DE CLÉS

ÉDIT du 30/05/2016 à 19h00 :

CONFIGURER GNUPG

Avant de générer une paire de clés, la première étape est d'avoir un bon fichier
gpg.conf avec les paramètres recommandés (utilisation des ID longs, affichage
des fingerprint, utilisation d'un cluster de serveurs de clés interrogés avec le
protocole sécurisé hkps, priorité aux algos forts, ...) car les paramètres par
défaut de GPG sont… insuffisants.

Même si vous utilisez Enigmail pour générer votre paire de clés, cette étape de
configuration est nécessaire !

GPG VERSION 1.X OU GPG VERSION 2.X ?

Pour l'usage quotidien, peu importe. gpg ou gpg2 fonctionnent de la même
manière, avec les mêmes commandes, respectent la même norme. Parmi les
différences, citons : la version 1 est monolithique (un seul binaire qui fait
tout) alors que la version 2 délègue du taff : dirmngr pour l'accès aux serveurs
de clés, libgcrypt pour les opérateurs cryptographiques,… D'après le manuel, la
version 2 est plus adaptée pour les environnements graphiques alors que la
version 1 est plus adaptée pour les utilisations en ligne de commande et les
utilisations automatiques. Les versions 2.X récentes apportent le support de
S/MIME et la gestion des courbes élliptiques.

Sous Debian GNU/Linux, gpg et gpg2 sont deux binaires différents qui
co-habitent. Sous ArchLinux, gpp pointe sur gpg2.

En revanche, ce qui va différer, c'est le bout de configuration concernant les
serveurs de clés : si l'on utilise gpg2, il faut créer un fichier
~/.gnupg/dirmngr.conf (si le dossier caché .gnupg n'existe pas, on le crée) avec
le contenu suivant en plus du fichier gpg.conf qu'on va créer plus loin :

hkp-cacert /etc/ssl/certs/hkps.pool.sks-keyservers.net.pem

Il faudra également vérifier que le logiciel dirmngr est bien installé, avec
apt-get, par exemple :

apt-get install dirmngr

CONFIGURATION COMMUNE À GPG VERSION 1.X ET GPG VERSION 2.X

Ensuite, il faut créer un fichier texte ~/.gnupg/gpg.conf (si le dossier caché
.gnupg n'existe pas, on le crée) avec le contenu suivant :

# Options for GnuPG
 
## Générales (https://raw.githubusercontent.com/ioerror/duraconf/master/configs/gnupg/gpg.conf)
# Uncomment the following option to get rid of the copyright notice
no-greeting
 
# Disable inclusion of the version string in ASCII armored output
no-emit-version
 
# Disable comment string in clear text signatures and ASCII armored messages
no-comments
 
 
## Crypto preferences (http://www.bortzmeyer.org/nouvelle-cle-pgp.html et https://raw.githubusercontent.com/ioerror/duraconf/master/configs/gnupg/gpg.conf)
# list of personal digest preferences. When multiple digests are supported by
# all recipients, choose the strongest one
personal-cipher-preferences AES256 AES192 AES
 
# list of personal digest preferences. When multiple ciphers are supported by
# all recipients, choose the strongest one
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
 
# For the keys we create / message digest algorithm used when signing a key
cert-digest-algo SHA512
 
# For the signatures and other things we generate
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed
 
 
## Serveur de clés (https://help.riseup.net/en/security/message-security/openpgp/best-practices#selecting-a-keyserver-and-configuring-your-machine-to-refresh-your-keyring)
# sks-keyservers.net mieux car checks de bon fonctionnement réguliers et hkps > *
keyserver hkps://hkps.pool.sks-keyservers.net
 
# https://sks-keyservers.net/sks-keyservers.netCA.pem
keyserver-options ca-cert-file=/etc/ssl/certs/hkps.pool.sks-keyservers.net.pem
 
# When creating a key, individuals may designate a specific keyserver to use to pull their keys from. 
# It is recommended that you use the following option to ~/.gnupg/gpg.conf, which will ignore such designations :
keyserver-options no-honor-keyserver-url
 
 
## Affichage des clés (https://help.riseup.net/en/security/message-security/openpgp/best-practices#selecting-a-keyserver-and-configuring-your-machine-to-refresh-your-keyring)
# Format long. Short OpenPGP Key IDs, for example 0×2861A790, are 32 bits long. They have been shown to be easily spoofed by another key with the same Key ID.
keyid-format 0xlong
 
# Long OpenPGP Key IDs (for example 0xA1E6148633874A3D) are 64 bits long. They are trivially collidable. If you want to deal with a cryptographically-strong identifier for a key, you should use the full fingerprint. You should never rely on the short, or even long, Key ID.
with-fingerprint

Attention : pour pouvoir utiliser le protocole sécurisé d'échange de clés hkps,
et si vous utilisez GPG 1.X, il faut installer le package « gnupg-curl ».

Attention : dans tous les cas (gpg 1.X ou 2.X), il faut récupérer le certificat
x509 de sks-keyservers.net dispo en
https://sks-keyservers.net/sks-keyservers.netCA.pem pour le stocker en
/etc/ssl/certs/hkps.pool.sks-keyservers.net.pem .

Fin de l'édit du 30/05/2016 à 19h00.

RÉELLEMENT GÉNÉRER VOTRE PAIRE DE CLÉS

À partir d'ici, vous pouvez utilisez Enigmail à la place des commandes barbares
que je propose ci-desous à condition d'utiliser une version d'Enigmail >= 1.8 !
Les versions inférieures générent des clés insufissantes pour 2016..

 * Générer une paire de clés :
   
   gpg --gen-key
   
   ÉDIT du 02/11/2014 à 16h00 : Choisir : RSA et RSA, une taille de 4096 octets.
   ÉDIT du 30/05/2016 à 14h30 : 4096 est une bonne taille encore aujourd'hui
   puisque l'ANSSI, via son référentiel général de sécurité (RGS) (document B1)
   indique que 2048 bits sont le minimum aujourd'hui pour des clés RSA et que
   3072 bits sont recommandés. La NSA indique 3072 bits minimum. Donc 4096 bits,
   c'est tout bon. Fin de l'édit du 30/05/2016.
   
   Ensuite, il faut préciser une date d'expiration d'un maximum de 2 ans. Cette
   date d'expiration, qui peut être vu comme étant facultative (si un certificat
   de révocation a été généré et stocké en lieu sûr, voir ci-dessous), ajoute
   pourtant une sécurité supplémentaire : si vous avez toujours votre clé
   privée, vous pourrez reporter la date d'expiration même après l'expiration
   (sans vous refaire une nouvelle paire de clés). Si vous n'avez plus votre clé
   privée (vol (copie + suppression quoi), compromission) et que vous n'avez pas
   généré le certificat de révocation (ou que vous l'avez perdu), alors vos
   correspondances et vos correspondants sont potentiellement menacés et la date
   d'expiration permet de réduire la durée d'exposition au danger de vos
   correspondants. L'expiration est aussi un moyen de résoudre les nombreux
   dysfonctionnements "par design" de la révocation dont le fait qu'il faut que
   tous vos contacts mettent à jour leur trousseau de clés pour que la
   révocation devienne effective. Retenez donc que l'expiration n'a rien en
   commun avec la révocation : la première est une sécurité (qui peut être
   contournée si elle s'active), la deuxième est définitive (une clé révoquée ne
   revient pas à la vie, en gros). Fin de l'édit du 02/11/2014.
   
   ÉDIT du 30/05/2016 à 20h15 : Ne pas indiquer de commentaire, c'est juste
   stupide / sans intérêt dans la plupart des cas…
   
   Saisissez une phrase de passe secrète solide car c'est sur elle que reposera
   la sécurité de vos échanges futurs. Pour qu'elle soit solide et mémorisable,
   utilisez la méthode Diceware avec un minimum de 5 mots qui n'ont rien à voir
   entre eux. De manière humoristique (mais tout à fait sérieux dans le fond),
   voir : https://xkcd.com/936/. Fin de l'édit.

 * Si la clé doit couvrir/fonctionner pour plusieurs "identités", notamment
   plusieurs adresses mails :
   
   gpg --edit-key "<fingerprint>"
   
   puis commande « adduid » pour ajouter toutes les identités/mail puis GnuPG:
   Selecting A Primary UID pour sélectionner l'identité principale. ÉDIT du
   30/05/2016 à 20h05 : Évidemment, toutes les identités/adresses mails que vous
   joigniez à la même clé GPG marque leur appartenance à une même clé privée
   donc à une même personne. Donc il ne faut pas utiliser la même clé GPG pour
   des adresses mails que vous ne voulez pas voir mélangées (perso / pro, par
   exemple ou perso / identité sur les sites porno). Fin de l'édit.

 * Générer le certificat de révocation en avance et le conserver précieusement à
   l'abri des regards indiscrets (utile en cas de gros pépin exposant vos
   contacts à une usurpation de votre identité) :
   
   gpg -o maclepgp.revoke --gen-revoke "<fingerprint>"
   
   ÉDIT du 02/11/2014 à 17h05 : Toute personne en possession de ce certificat
   pourra révoquer votre paire de clés sans aucun contrôle (pas de demande de
   passphrase, par exemple) donc faites très attention ! Une révocation est
   définitive et elle empêchera tout ordinateur la connaissant de chiffrer des
   mails à votre intention ! Voir la section « Révoquer une paire de clés avec
   un certificat de révocation » à la fin de ce billet pour plus d'informations.
   Fin de l'édit.

 * Exporter la clé publique (pour un test avec une clé de test, par exemple) :
   
   gpg -a -o maclepgp.pub --export "<fingerprint>"
   
   Pour info : « -a | --armor : Create ASCII armored output. The default is to
   create the binary OpenPGP format. »

 * Publier la clé publique sur un serveur de clés (pour la vraie clé de
   production, c'est LA méthode à utiliser) :
   
   gpg --send-key "<fingerprint>"

 * Vous pouvez générer des sous-clés mais ce n'est pas aussi trivial que le
   sous-entendent les tutoriels. Pour un début, je m'en passerai. Pour la
   sécurité, mieux vaut des outils cryptos compris que des fonctionnalités
   supplémentaires incomprises. Par défaut, GPG génère une sous-clé de
   chiffrement en plus de la clé de signature.
 * Pensez à sauvegarder un maximum de chose : tout le dossier .gnupgp ainsi
   qu'un export de la clé privée :
   
   gpg --export-secret-keys -a -o maclepgp.private "<fingerprint>"
   
   et à stocker tout ça à l'abri des regards indiscrets ! Pensez à sauvegarder à
   chaque signature d'une clé (la votre ou celle d'autrui).


CHIFFRER/DÉCHIFFRER/SIGNER/VÉRIFIER LA SIGNATURE (D')UN FICHIER

 * Chiffrer un fichier :
   
   gpg -ae <fichier>
   
   Le champ « choisir le destinataire » est un champ de recherche (accepte la
   fingerprint, une partie de l'identité, ...).

 * Déchiffrer un fichier :
   
   gpg -ad <fichier>
   
   Ajouter « -o » pour avoir la sortie dans un fichier au lieu de stdout.

 * Chiffrer et signer un message en même temps :
   
   gpg -ase <fichier>

 * Déchiffrer en vérifiant la signature : pareil qu'un déchiffrement sans
   signature. GPG indiquera simplement en plus s'il a réussi à vérifier la
   signature ou non.
 * Signer uniquement un fichier (« --clearsign » peut aussi être utile s'il faut
   garder le texte clair et signer à côté) :
   
   gpg -as <fichier>

 * Vérifier la signature (il faut bien évidemment avoir d'abord importé la clé
   publique correspondant à la clé privée qui a générée la signature, ce qui est
   le cas ici ; On voit souvent ce mécanisme avec les sources des logiciels
   libres sérieux) :
   
   gpg --verify <fichier>.(sig|asc)

Des personnes utilisent OpenPGP pour chiffrer certains de leurs fichiers qu'ils
ne vont pourtant transmettre à personne (exemple : fichier de mots de passe).
Est-il mieux d'utiliser OpenSSL ou GPG pour réaliser cette opération ? Je n'ai
aucune réponse définitive. Pour moi, les deux outils sont équivalents. Et sur
cet aspect-là, la CLI GPG est plus conviviale que la CLI OpenSSL.

ÉDIT du 30/05/2016 à 17h15 :


STOCKER VOS MOTS DE PASSE

Hé oui, GPG vous permet de constituer un gestionnaire de mots de passe à la
KeePassX : stockez vos mots de passe dedans, sous forme chiffrée. Pour accéder à
votre trousseau de mots de passe, il faut votre clé privée OpenPGP et sa phrase
de passe.

Le gestionnaire de mots de passe utilisant GPG que j'apprécie et que je
recommande se nomme pass. Voir sur mon shaarli pour un avis détaillé : Pass: The
Standard Unix Password Manager - GuiGui's Show - Liens.

Fin de l'édit.


TROUVER LA CLÉ PUBLIQUE D'UN CORRESPONDANT, LA VÉRIFIER ET L'AJOUTER À VOTRE
TROUSSEAU

Méthodes pour obtenir la clé publique d'un correspondant :

 * Chercher une clé sur un serveur de clés :
   
   gpg --search-keys "<ID ou une partie de l'identité>"
   
   L'import est proposé si la recherche réussit. Il faudra vérifier la
   fingerprint (vérifier le lien entre une clé et son titulaire supposé) de
   cette clé via, au pire, l'utilisation d'un un canal alternatif (téléphone,
   XMPP,...) ou en se reposant sur le graphe de relations (une connaissance
   commune en qui vous avez confiance tous les deux qui aurait signé vos clés au
   préalable), au mieux : une rencontre de visu (AFK). À ce titre, je rappelle
   qu'une identité, en droit français, ça ne se vérifie pas nécessairement par
   des documents d'état civil mais aussi par au moins 2 témoignages. 😉

 * À partir d'une fingerprint :
   
   gpg --recv-key "<fingerprint>"
   
   Là aussi, il faut forcément vérifier la fingerprint.

 * À partir d'un fichier :
   
   gpg --import <cleducorrespondant>.asc
   
   Il faut vérifier la fingerprint.

Commandes utiles :

 * Voir le trousseau :
   
   gpg --list-keys 
   gpg --list-sigs

 * Voir la fingerprint d'une clé :
   
   gpg --fingerprint <keyID>

 * Supprimer une clé de votre trousseau :
   
   gpg --delete-key "<fingerprint>"

 * Signer une clé et lui accorder un niveau de confiance :
   
   gpg --edit-key "<fingerprint>"
   
   puis commande « sign » puis choisir un degré de confiance, normalement 3 ou
   4, puis « quit ».

 * Publier le graphe des relations (les clés que vous avez signées) :
   
   gpg --send-key "<fingerprint>"
   
   Ici « fingerprint » désigne l'empreinte de chaque clé que vous avez signé
   puisque votre signature apparaît sur leur clé (--list-sig). Ne pas indiquer
   de fingerprint pousse toutes les clés sur le serveur de clés (sauf celles
   signées localement, voir ci-dessous). Source : Distributing keys - The GNU
   Privacy Handbook. Corollaire : vous devez "--refresh-keys
   <votre_fingerprint>" pour avoir, dans votre trousseau local, les signatures
   que d'autres personnes ont apposé à votre clé.

 * Il est possible de signer localement une clé, c'est-à-dire, de la signer sans
   que la signature soit exportée sur un serveur de clés. Cela permet de masquer
   une partie de votre graphe de relations. Lors d'un échange de clés, il est
   important de demander à votre interlocuteur s'il souhaite que vous
   apparaissisez dans son graphe de relations et inversement. Ça permet aussi ne
   pas conduire autrui (si autrui utilise le modèle de la toile de confiance) si
   vous souhaitez importer une clé sans faire les vérifications qui s'imposent
   normalement. Tout ça en évitant les demandes de confirmation (voire d'erreur)
   de votre MUA. Pour se faire :
   
   gpg --edit-key "<fingerprint>"
   
   puis juste les commandes « lsign » et « quit ».

 * Grâce à la toile de confiance, il est possible pour deux interlocuteurs ayant
   une (ou plusieurs) relations en commun (qui ont signées leurs clés) de
   vérifier leurs identités respectives sans pour autant avoir communiqué sur un
   canal sécurisé. On notera qu'utiliser ce mécanisme nous rend vulnérables aux
   vérifications effectuées par les relations communes : comment ont-elles signé
   les clés ? Selon quels critères ? Peut-on vraiment avoir confiance en leur
   process ? Il est donc de l'appréciation de chacun de recourir ou non à la
   toile de confiance.
 * ÉDIT DU 10/06/2016 À 19H40 : Visualiser votre graphe de relations / votre
   toile de confiance en utilisant sig2dot . FIN DE L'ÉDIT.


CHIFFRER/DÉCHIFFRER/SIGNER/VÉRIFIER LA SIGNATURE (D')UN MAIL

Comme j'utilise principalement Icedove, j'ai pris la bien connue extension
enigmail. Installée via apt-get puis chargée automatiquement après un
redémarrage d'Icedove. L'assistant est convivial, rien à détailler. ÉDIT du
30/05/2016 à 15h30 : Ce n'est pas une bonne idée : sous Debian Wheezy, on avait
Enigmail 1.7.X alors que la version 1.8 apportait d'énormes changements (rsa
4096 par défaut, expiration = maintenant + 5 ans, proposition appuyée pour faire
générer le certificat de révocation, etc.). Il vaut donc mieux installer
l'extension comme toute extension, depuis addons.mozilla.org. Fin de l'édit.

ÉDIT du 30/05/2016 à 15h30 : Attention, le couple Thunderbird+Enigmail n'est pas
forcément le plus sécurisé.

D'une part, Enigmail est une extension de Thunderbird, ce qui signifie que les
fonctionnalités qu'elle apporte n'ont pas été prévues par les développeurs-euses
de Thunderbird, ce qui signifie qu'Enigmail est un contournement crade du
cheminement normal de l'envoi d'un mail avec Thunderbird : Enigmail intercepte
l'envoi d'un mail, fait sa tambouille, ré-injecte le mail à envoyer. Même si ça
fonctionne, ce comportement n'est pas sain.

D'autre part, le format d'un mail, le format MIME, est démoniaque. Un mail est
toujours composé d'une partie entêtes et d'une partie corps mais le corps peut
être subdivisé. C'est le cas quand il y a un message + une pièce jointe ou quand
le mail est envoyé dans une version texte ET dans une version HTML pour plaire à
tout le monde. C'est aussi le cas quand un mail est chiffré ou signé avec PGP et
qu'on utilise PGP/MIME : la signature / le texte chiffré est dans un
compartiment séparé logé dans le corps du mail. Là où ça se complique, c'est que
l'enchaînement et l'imbrication de parties MIME peuvent aller assez loin.
L'ennui, c'est qu'Enigmail informe très mal de quelles parties du mail sont
chiffrées / signées. Exemple bateau : rédiger un mail au format plain/text,
coller un blob PGP au milieu, Engimail avertira que TOUT le mail est signé alors
que seul le blob PGP l'est. Ça peut amener à des tromperies des
utilisateurs-trices du genre le corps du mail, celui qui s'affiche, que
l'utilisateur lit, est nullement signé, seule un autre compartiment dans le mail
l'est donc l'utilisateur-trice n'a aucune garantie sur l'authenticité et
l'intégrité du corps du mail qu'il-elle lit ! Exemple concret ici : KMail
indique clairement les parties qu'il n'a pas traité alors qu'Enigmail affiche le
bandeau vert "toutVaBien".

Bref, notons que chaque logiciel mail dispose de son propre frontend à PGP et
que tous ne se valent pas.
Fin de l'édit.

Enigmail fait le travail de déchiffrement et/ou vérification des signatures
automatiquement à la réception d'un mail :

 * Si vous obtenez le message « Message déchiffré; Signature non vérifiée;
   cliquez sur l'icône « stylo » », ne cherchez pas l'icône stylo mais cliquez
   sur « détails » à droite de ce bandeau d'information. Vous n'avez pas la clé
   publique de votre correspondant dans votre trousseau.
 * Si vous obtenez le message « [...] Signature non certifiée [...] », alors
   vous n'avez pas signé la clé publique de votre correspondant.
 * « Message déchiffré; Signature correcte de [...] ». Tout est ok \o/ .
 * Je n'ai pas encore rencontré les autres messages (déchiffrement impossible,
   par exemple).

ÉDIT du 30/05/2016 à 19h45 : Attention : Enigmail permet également de générer
facilement une paire de clés de manière conviviale mais il est impératif de
configurer GPG au préalable car les paramètres par défaut sont insuffisants.
Voir la première partie de ce billet. Fin de l'édit.

Pour envoyer un mail avec du contenu chiffré et/ou signé, on peut aussi utiliser
les méthodes précédentes sur les fichiers puis

mail -s "" <adresse_mail_destinataire> < <fichier>.asc

Mais ce n'est pas vraiment sérieux. 😀

QUELQUES PRÉCAUTIONS À PRENDRE LORS DE L'ENVOI D'UN MAIL SIGNÉ/CHIFFRÉ

 * PGP/inline ou PGP/MIME ? Voir : Choisir PGP/MIME ou PGP/Inline chez Vigdis et
   Choisir PGP/MIME ou PGP/Inline chez le Hollandais Volant pour un exposé des
   différents arguments. Je retiens que pour la signature, on se pose aucune
   question : PGP/MIME. Pour un mail chiffré, il faut se décider à prendre en
   compte les MUA en carton (au détriment de la sécurité) ou pas. Pensez à
   configurer votre MUA. Pour Icedove/Enigmail, voir : Enigmail Configuration
   Manual - Per Account Settings. Sous Debian GNU/Linux Wheezy, je remarque que
   PGP/MIME est utilisé par défaut.
 * Dans tous les cas, le sujet du mail n'est pas chiffré (comme le reste des
   en-têtes), il faut donc éviter de mettre l'information confidentielle dedans.
   Évidemment, cela rend plus difficile l'estimation de la priorité (du point de
   vue du destinataire donc exit le header posé par l'expéditeur) d'un mail et
   la recherche. Compromis entre simplicité et sécurité, as usual.
   
   J'en profite pour rappeler que les métadonnées (adresse d'expédition,
   adresses destinataires (même CCi), heure, poids, fréquence des échanges) sont
   vues par tous les intermédiaires entre vous et votre correspondant. OpenPGP
   ne change pas ça !
   
   * PGP = contenu chiffré/signé de bout en bout ;
   * TLS = chiffrement point à point entre deux serveurs SMTP. Les métadonnées
     ne circulent donc plus en clair, seuls les MTA sur le chemin voient les
     métadonnées ;
   * Autohébergé + TLS + PGP = le top : métadonnées connues exclusivement des
     serveurs SMTP de l'expéditeur et du destinataire, métadonnées (+ contenu,
     of course) chiffrées entre les serveurs et contenu protégé de bout en bout
     par PGP. Notons qu'il suffit de tcpdump, au niveau 3, en amont d'un serveur
     mail personnel, autohébergé ou non, pour savoir qui écrit à qui, quand à
     quelle heure, à quelle fréquence : pas besoin de virer TLS ni de pirater
     les serveurs de mails. Bah oui, on sait que le serveur A avec l'IP A est à
     GuiGui... Forcément, tout mail qui en sort est émis par GuiGui, tout mail
     qui entre est à destination de GuiGui.
 * Les pièces jointes non incluses dans le corps du mail laissent leur nom
   apparaître même avec PGP donc, pareil que pour le sujet : ne pas y mettre la
   fameuse information confidentielle. Cf : Parce que vous vous foutez de vos
   libertés, ce sont les miennes qui disparaissent. Apparemment, ce comportement
   dépend du MUA : Mutt ne fait pas fuiter le nom des pièces jointes, par
   exemple.
 * Si vous perdez votre clé privée, c'est mort pour déchiffrer les mails, même
   les mails échangés dans le passé ! Faites attention avec votre trousseau et
   sauvegardez-le bien !

ÉDIT du 30/05/2016 à 16h30 :

QUID DES WEBMAILS ?

Utiliser un webmail avec OpenPGP est une mauvaise idée.

Déjà, ça suppose que, même si le webmail ne rapatrie pas vos mails sur la
machine que vous utilisez, il vous faut quand même votre clé privée sur la
machine que vous utilisez afin de déchiffrer les mails entrants et de signer les
mails sortants. Si vous êtes au taff et que votre disque dur n'est pas chiffré
OU que votre boss (ou une équipe de votre société) est root sur votre machine,
il est hors de question de stocker votre clé privée sur cette machine, de base.
Donc usage webmail ou pas, ce n'est pas la question. En revanche, si vous avez
un moyen de stockage externe de votre clé privée (pas sur une clé USB, hein,
root peut toujours vous voler votre clé privée :- ) duquel la clé ne sort jamais
comme une Yubikey 4 (les versions d'avant gèrent uniquement des clés de 2048
bits max, ce qui est pourri de nos jours) alors vous n'êtes pas concerné-e par
ce premier point mais…

Ensuite, ça suppose que le webmail, qui n'est autre qu'une page web distante,
puisse exécuter du code sur votre machine. Cela se fait avec JavaScript. Peut-on
avoir confiance en un langage exécuté sur votre machine mais réellement piloté
par le webmail distant, c'est-à-dire par une machine hors de chez vous, hors de
votre contrôle ? Même quand il s'agit de manipuler votre clé privée (qui doit
rester privée, je le rappelle) ? Même quand il s'agit de chiffrer/déchiffrer ?

Un cas concret met en évidence quelques problèmes qui peuvent survenir : Tails -
FireGPG susceptible to devastating attacks :

> Webmail interfaces commonly use text boxes for email composition, so FireGPG
> is a natural fit for this use case: the user writes his or her email plaintext
> in the text box, selects the plaintext and uses one of the "Encrypt" or "Sign
> and encrypt" actions available from the FireGPG menu to transform the
> selection to its encrypted counterpart.
> 
> The FireGPG design incorrectly assumes that this is safe, but it is not, since
> JavaScript running on the page can still control and observe much of what is
> happening on the page. For instance, a simple script can set up a timer that
> silently submits the contents of the text box back to the server every second,
> thereby leaking the plaintext as it is written, effectively bypassing any
> subsequent encryption. In fact, many non-malicious webmail services do just
> that at longer intervals, to save a draft of a message in case the user's
> browser crashes.
> 
> [...]
> 
> FireGPG also has three commands to sign (but not encrypt) messages: "Sign",
> "Wrapped sign" and "Clearsign". Simple JavaScript can replace the contents of
> the text box when the user selects it, so if the user does not re-read the
> text after selecting one of the 'sign' commands, the attacker will be able to
> obtain the user's signature on an arbitrary message.

Quant à Mailvelope, c'est totalement basé sur un framework JavaScript,
OpenPGP.js… Pour ma part : problème de confiance envers JavaScript.

Enfin, même si vous chiffrez/signez votre prose en local avant de copier le blob
GPG dans un webmail (ce que fait l'applet GPG de Tails), un webmail utilise
forcément PGP/Inline et on a vu ci-dessus que ce n'était ni le plus sécurisé ni
le top visuellement parlant. Ça concerne tous les webmails : Roundcube,
Mailpile,…

Pour qu'un webmail puisse gérer PGP/MIME, il n'y a que deux méthodes possibles :
soit votre clé privée est stockée sur le serveur de mails, soit il faut
implémenter un parseur MIME en Javascript qui s'exécutera uniquement côté
client. Dans le premier cas, ça pourrait convenir uniquement aux serveurs de
mails qui ne sont pas mutualisés entre plusieurs utilisateurs. Et encore : il
existe un risque de se faire voler sa clé privée OpenPGP via un logiciel pas à
jour et/ou une faille dans un site web présent sur le même serveur, par exemple.
Dans le deuxième cas, quitte à ré-implémenter un parseur MIME, autant avoir un
client mail lourd. Surtout que recoder un parseur MIME n'est pas simple, il y
aura des bugs, des failles, etc.


OPENPGP ET CONFIDENTIALITÉ PERSISTANTE (PFS - PERFECT FORWARD SECRECY)

Contrairement à OTR ou à TLS ou SSH, OpenPGP ne peut pas apporter la
confidentialité persistante : si votre clé privée est volée, le voleur peut, une
fois qu'il a la passphrase : 1) déchiffrer tout contenu chiffré ultérieurement
avec la clé publique, 2) signer du contenu, 3) déchiffrer tout contenu produit
antérieurement au vol qui tomberait sous sa main. Ainsi, si vos mails et votre
clé privée sont volés, c'est la fin : tous vos échanges passés sont connus par
le voleur. Avec la PFS, le 3) est évité.

OpenPGP ne peut pas apporter cette propriété de confidentialité persistante car
elle suppose un échange synchrone pour se transmettre une clé de chiffrement
temporaire. Or, le mail n'est pas prévu pour être synchrone.

FIN DE L'ÉDIT du 30/05/2016 à 16h30

ÉDIT DU 05/07/2016 À 17h00


CHANGER LA DATE D'EXPIRATION D'UNE CLÉ

Votre clé arrive bientôt à expiration voire elle a expiré ? Voici comment
repousser la date d'expiration.

EN LIGNE DE COMMANDE

gpg --edit-key "<fingerprint_de_votre_clé"

Pour changer la date d'expiration de votre clé principale :

expire

Je recommande de repousser la date d'un an, surtout si vous êtes un-e novice : à
ce stade, on perd souvent sa clé privée et cert' de révocation donc ce n'est pas
la peine d'avoir une date d'expiration de 2 ou 5 ans… Donc, on indique « 1y » à
GPG. Puis on confirme notre choix et on saisit notre phrase de passe pour que la
modification prenne effet.

Ensuite, il faut s'occuper de chacune de vos sous-clés. Pour les voir, il faut
utiliser la commande « list ». Par défaut, GPG crée une sous-clé de chiffrement.
Il faut donc la renouveller elle-aussi.

D'abord, on la sélectionne (clé qui porte l'index, le numéro 1):

key 1

Ensuite, on recommence le topo : expire , 1y, on confirme.

Il faut faire cela pour chaque sous-clé.

Une fois que cela est fait, on sauvegarde nos changements :

save

Avant-dernière étape, mettre à jour notre clé sur les serveurs de clés pour que
nos contacts puissent prendre connaissance que notre clé ne va pas expirer cette
fois-ci et qu'ils peuvent continuer à l'utiliser :

gpg --send-key "<fingerprint_de_votre_clé>

Dernière étape : comme toujours, il faut penser à sauvegarder l'intégralité de
votre trousseau (tout le dossier .gnupg, en gros) + une copie de votre clé
privée modifiée. Voir la fin de la partie « Générer une paire de clés » pour
avoir la commande d'export qui fait ce job.

AVEC ENIGMAIL

Il faut aller dans l'item « Gestion de clés » du menu « Enigmail » puis cliquer
droit sur votre clé (facile de la reconnaître, elle est en gras) et choisir «
Changer la date d'expiration » dans le menu. Par défaut, Enigmail sélectionne
votre clé principale + sa sous-clé de chiffrement et propose de reporter la date
d'expiration d'une année, c'est un bon choix donc on se contente de valider.

FIN DE L'ÉDIT du 05/07/2016 À 17h00

ÉDIT du 02/11/2014 à 17h15 :


RÉVOCATION

Je parle ici d'une révocation voulue : nous changeons de clés car l'ancienne clé
à fait son temps (exemple : taille de clé devenue trop faible avec le temps,
avancées cryptanalyse, ...) ou n'a pas été générée avec les paramètres
recommandés permettant d'assurer un minimum de sécurité. Évidemment, les
fichiers et mails chiffrés avec votre ancienne clé doivent rester lisibles.

Évidemment, je vous recommande très fortement de sauvegarder votre trousseau
(tout le dossier ~/.gnupg quoi) avant de commencer. Tant que vous n'avez pas
propagé vos modifications sur un serveur de clés (commande « gpg --send-key »),
vous pouvez toujours restaurer votre ancien dossier .gnupg pour revenir en
arrière. Une fois les modifications poussées sur un serveur de clés, c'est trop
tard, notamment pour la révocation donc vérifiez bien vos manipulations avant de
procéder à cet envoi.

Cette section est inspirée de : Révoquer une clé GnuPG - Sima78.

GÉNÉRER UNE NOUVELLE PAIRE DE CLÉS

La première étape est de générer une nouvelle paire de clés. Je vous recommande
de lire la section « Générer une paire de clés » en haut de ce billet à propos
de la conf recommandée pour GnuPG et de comment on génère/sauvegarde une paire
de clés et le certificat de révocation associé. Ci-dessous, je fais le strict
minimum concernant la génération d'une nouvelle paire de clés.

On génère une nouvelle paire de clés :

gpg --gen-key

On signe notre nouvelle clé avec notre ancienne clé :

gpg --default-key <fingerprint_ancienne_clé> --sign-key <fingerprint_nouvelle_cle>

Cela permet d'indiquer à tout le monde que c'est bien votre nouvelle clé à vous
(vous l'avez signée). Cela est purement indicatif : en effet, en cas de
compromission totale (récupération de votre clé privée et de sa passphrase), la
personne mal-intentionnée peut très bien générer une nouvelle paire de clés et
la signer avec votre ancienne paire de clés histoire de tromper vos
correspondants avant que vous vous rendiez compte de la compromission et que
vous les préveniez. L'avantage de procéder ainsi pour l'attaquant est qu'il
commence une nouvelle chaîne de confiance sous son contrôle.

On publie la partie publique sur un serveur de clés :

gpg --send-key <fingerprint_nouvelle_cle>

TESTER LA NOUVELLE PAIRE DE CLÉS

Avant d'aller plus loin, il faut tester notre nouvelle paire de clés.

Pour que GnuPG utilise votre nouvelle paire de clés par défaut (sans qu'on ai
besoin de lui indiquer « --default-key » à chaque commande), il faut modifier le
fichier gpg.conf pour ajouter la ligne suivante :

default-key "fingerprint_nouvelle_clé"

Ce morceau de configuration ne sera plus utile une fois l'ancienne clé révoquée
: GnuPG ignorera l'ancienne clé sauf pour déchiffrer / vérifier la signature
d'anciens fichiers/mails.

Pour que Thunderbird/Enigmail utilisent votre nouvelle paire de clés : menu «
Édition », « Paramètres des comptes », choisir le compte mail dans la liste à
gauche, « Sécurité OpenPGP ». Cocher « Utiliser un identifiant de clé
particulier », cliquer sur le bouton « Choisir une clef ... » et choisir la
nouvelle clé.

À ce stade, vos anciens fichiers et mails chiffrés/signés sont encore
parfaitement lisibles et vérifiables. Votre nouvelle clé vous permet de
chiffrer/signer des fichiers et des mails. Chez vos correspondants, Enigmail
affiche « Signature non vérifiée » : c'est normal, ils doivent importer et
signer votre nouvelle partie publique.

RÉVOQUER L'ANCIENNE CLÉ

gpg --edit-key "<fingerprint_ancienne_clé>"
[...]
gpg> revkey

Confirmez que vous voulez vraiment révoquer cette clé, choisissez la raison « 2
= La clé a été remplacée », vous pouvez indiquer une raison comme « taille de
clé insuffisante » puis confirmez que vous êtes d'accord avec la touche « o »
puis tapez la commande « save » puis « quit ».

Vous pouvez vérifier que votre clé a bien été révoquée avec les commandes
habituelles comme « --list-keys ».

Si tout est OK, vous pouvez pousser votre clé révoquée sur les serveurs de clés.
Attention, la révocation devient définitive à partir d'ici !

gpg --send-key <fingerprint_ancienne_clé>

Quand je vous ai dit que la révocation est devenue effective à ce stade, je vous
ai un peu menti : elle sera effective quand tous vos contacts auront mis à jour
leur trousseau. En attendant qu'ils le fassent, ils peuvent toujours utiliser
votre ancienne clé publique pour vous envoyer des mails/fichiers chiffrés alors
qu'elle a pourtant été révoquée. D'où l'importance de mettre à jour
régulièrement son trousseau de clés : « gpg --refresh-keys » ou, mieux pour la
confidentialité de votre graphe de relations, parcimonie.

Voilà, on a terminé. \o/

À ce stade, vous pouvez toujours déchiffrer/vérifier vos anciens mails/fichiers.
L'ancienne clé n'est plus utilisable, ni dans GnuPG directement ni dans Enigmail
pour chiffrer/signer de nouveaux fichiers/mails. Si vous tentez quand même de
signer un mail avec votre ancienne clé privée, Enigmail vous hurle dessus : «
L'adresse de courriel ou ID de clé '<lala>' ne correspond pas à une clé OpenPGP
valide et non-expirée. ». \o/

Évidemment, tous vos correspondants doivent signer votre nouvelle clé publique.
🙂

Évidemment, ne vous amusez pas à supprimer l'ancienne clé de votre trousseau !
Si vous le faîtes, vos anciens mails et fichiers chiffrés sont perdus
(illisibles) ! À titre d'information, les commandes dangereuses à ne pas faire
(mais GnuPG crache plein d'avertissements pour vous convaincre de faire marche
arrière) sont : « --delete-secret-keys <fingerprint> » puis « --delete-key
<fingerprint> ».

RÉVOQUER UNE PAIRE DE CLÉS AVEC UN CERTIFICAT DE RÉVOCATION

Ci-dessus, nous avons vu comment révoquer une paire de clés avec la commande «
revkey ». Voyons maintenant comment faire dans la pire hypothèse : vous n'avez
plus votre clé privée, vous avez une machine vierge et vous avez votre
certificat de révocation.

D'abord, il faut importer la clé publique à partir d'un fichier ou d'un serveur
de clés :

gpg --import <ma_cle_pgp_pwned>.asc
OU
gpg --search-keys "<ID_ou_une_partie_de_l'identité>"

Ensuite, il faut importer le certificat de révocation :

gpg --import maclepgp.revoke

On vérifie que tout est OK avec les commandes habituelles comme « --list-keys ».

Si tout est OK, vous pouvez pousser votre clé révoquée sur les serveurs de clés.
Attention, la révocation devient définitive à partir d'ici !

gpg --send-key <fingerprint_ancienne_cle>

Fin de l'édit.


CONCLUSION

OpenPGP et ses implémentations, ce n'est pas encore accessible à tous, comme
tout ce qui tourne autour de la sécurité.

Je déconseille le tutoriel La cryptographie facile avec PGP sur le SdZ notamment
à cause du paragraphe suivant (vers la fin) : « Normalement, toutes les clés
devraient être signées par d'autres, elles-mêmes signées par d'autres, et ainsi
de suite jusqu'à arriver à quelques personnes fiables comme Phil Z (l'inventeur
de PGP), Linus Torvalds (le créateur de Linux) ou Richard Stallman (le fondateur
de GNU) : ce réseau reliant les clés entre elles est appelé réseau de confiance
(web of trust). ». Le modèle de la toile de confiance n'a rien en commun avec le
modèle hiérarchique des AC x509 bien connues !

Tout ça pour dire d'être prudent lorsque l'on parle de crypto. 🙂


Catégorie: Divers, Sécurité / Tags: aucun tag / Commentaires fermés sur Ma
première (vraie) clé PGP
« Entrées précédentes




 * ARCHIVES :
   
   décembre 2023 L M M J V S D  123 45678910 11121314151617 18192021222324
   25262728293031
   
   « Oct    


 * CATÉGORIES
   
   * Administration réseau
   * Administration système
   * BGP & RPKI+ROA
   * Blog
   * Cinéma/TV
   * Développement
     * Assembleur 8086+
   * Divers
   * DNS & DNSSEC
   * Hardware
     * Embarqué
       * OpenWRT
   * Humeur
   * Jeux vidéo
   * Logiciels
   * Sécurité


hoplala Le contenu de ce blog est mis à disposition sous un contrat Creative
Commons BY-SA 3.0 France. Exception faite des commentaires, des extraits de
textes, médias et marques qui restent la propriété de leurs auteurs respectifs.
Toute copie de ce site doit mentionner http://www.guiguishow.info. Publié avec
WordPress. Pyrmont V2