Tutoriel portail captif Kanet

réf : http://code.google.com/p/kanet/

version testée : kanet 0.2.3 sur ubuntu 10.04 LTS lucid lynx x86_32


Introduction

Le but de ce tutoriel est de détailler une façon d'installer le portail captif Kanet développé par Cyrille Colin de l'Université de Metz avec une authentification sur CAS (Central Authentication Server) pour commencer.

L'installation se fait sur une version Ubuntu Server LTS 10.04, sur une machine disposant de deux interfaces réseaux eth0 et eth1.
Eth0 est reliée au réseau "public". C'est la partie externe à la zone que l'on veut capturer, c'est l'interface de sortie de notre routeur. Elle a, dans cet exemple, l'IP : 192.168.8.2. Vous pouvez déjà oublier cette interface, il ne lui sera consacré que quelques lignes pour sa configuration initiale.
Eth1 est reliée au réseau privé, celui dont on cherche à capturer le trafic (on l'appellera "réseau captif" dans la suite de ce tutoriel) et à l'authentifier. Elle a pour adresse ici : 192.168.200.1.

On possède déjà dans notre infrastructure un serveur DNS (192.168.100.50) et un serveur proxy/cache web (avec squidguard). On va donc juste demander au serveur Kanet de se comporter comme un serveur dhcp pour le réseau captif et comme un relai DNS (forwarder) vers notre DNS.

Kanet peut fonctionner en mode STAND_ALONE, seul sans dépendance, ou en mode PROXY.
Dans ce dernier cas, Kanet sera placé derrière un reverse proxy Apache qui lui relaiera les requêtes http.

Kanet est capable d'authentifier les utilisateurs de plusieurs façons différentes : via un serveur Radius, via un serveur CAS, via un serveur Shibboleth ou selon une combinaison de deux ou trois des méthodes précédentes simultanément. Le mode PROXY est obligatoire pour l'utilisation de l'authentification Shibboleth.
Bien qu'on ne détaille que l'authentification sur CAS dans ce tutoriel, on choisit néanmoins le mode PROXY dès à présent afin de préparer une future utilisation éventuelle de Shibboleth.

Le réseau

Comme expliqué dans le résumé au dessus, on configure les deux interfaces eth0 et eth1 sur les deux réseaux, le "public" et le "captif" :
/etc/network/interfaces
auto lo
iface lo inet loopback

# interface publique
auto eth0
iface eth0 inet static
        address 192.168.8.2
        netmask 255.255.255.0
        network 192.168.8.0
        broadcast 192.168.8.255
        gateway 192.168.8.1
        # dns-* options are implemented by the resolvconf package, if installed
        dns-nameservers 192.168.100.50
        dns-search iut.rdz


# interface du réseau captif
auto eth1
iface eth1 inet static
        address 192.168.200.1
        netmask 255.255.255.0
        network 192.168.200.0
        broadcast 192.168.200.255

Et on relance pour prendre en compte la configuration :
/etc/init.d/networking restart

Installation

On installe et on configure d'abord les pré-requis :
apt-get install libsqlite3-0 libjson-glib-1.0-0 libglib2.0-0 libgee2 libsoup2.4-1 libradiusclient-ng2 libnetfilter-conntrack3 libnetfilter-queue1 shared-mime-info libdaemon0
Puis le paquet kanet lui-même :
dpkg -i kanet_xxx.deb

Pour mon tutoriel, j'ajoute les serveur dhcp et DNS :
apt-get install dhcp3-server bind9
que je configure rapidement d'une part pour servir des adresses sur la plage 192.168.100.10-255 pour le dchp:
/etc/dhcp3/dhcpd.conf
ddns-updates off;
option domain-name-servers 192.168.200.1;

default-lease-time 600;
max-lease-time 7200;
authoritative;

subnet 192.168.200.0 netmask 255.255.255.0 {
option routers 192.168.200.1;
option broadcast-address 192.168.200.255;
range 192.168.200.10 192.168.200.255;
}

d'autre part, pour relayer les requêtes vers mon serveur DNS existant :
/etc/bind/named.conf.options
options {
directory "/var/cache/bind";

listen-on {192.168.200.1; };
forwarders {192.168.100.50; };

auth-nxdomain no; # conform to RFC1035
listen-on-v6 { any; };
};

Puis je relance ces services afin de prendre en compte ces configurations :
/etc/init.d/bind9 restart
/etc/init.d/dhcp3-server restart

Enfin on installe un serveur apache et on active quelques modules qui vont être nécessaires :
apt-get install apache2
a2enmod rewrite
a2enmod proxy
a2enmod proxy_http
a2enmod ssl

La plateforme est désormais prête. On peut passer à la configuration de Kanet et du redirecteur Apache.

Configuration

La configuration du serveur se répartit sur trois secteurs :
  • les règles IPTable,
  • le réglage et le comportement du serveur kanet,
  • les règles de redirection http Apache.

Les règles IPTable

L'exemple donné sur le site fonctionne à merveille. On le reprend directement tel quel en n'oubliant pas de préciser notre interface (eth1) et notre adresse (192.168.200.1) côté réseau captif :

vi /etc/init.d/kanet-rules

#!/bin/sh
 
IPT
="/sbin/iptables"

IP_PRIVATE
="192.168.200.1"
NTINT
="eth1"
 
test
-f $IPT || exit 0
 
case "$1" in
        start
)
    echo
-n "Loading kanet firewall's rules: "
    echo
1 > /proc/sys/net/ipv4/ip_forward
 
   
# Flush table
    $IPT
-t nat -F
    $IPT
-t mangle -F
    $IPT
-t filter -F
 
 
    $IPT
-t mangle -A PREROUTING -i $NTINT -j CONNMARK --restore-mark
    $IPT
-t mangle -A PREROUTING -p TCP -i $NTINT -d $IP_PRIVATE -j ACCEPT
    $IPT
-t mangle -A PREROUTING -p TCP -i $NTINT -m state --state NEW -j QUEUE
 
 
 
    $IPT
-t nat -A PREROUTING -p TCP -i $NTINT -j CONNMARK --save-mark
   
# MARK 0xFFFFFFFF = Openacls
    $IPT
-t nat -A PREROUTING -p TCP -i $NTINT -m mark --mark 0xFFFFFFFF -j ACCEPT
 
   
# MARK 0xFFFFFFFE = use http-to-https redirection (Not implemented)
   
#$IPT -t nat -A PREROUTING -p TCP -i $NTINT -m mark --mark 0xFFFFFFFE -j DNAT --to-destination $IP_PRIVATE
 
   
# MARK 0x0 = unauthenticated - 80 is redirected to authentication page
    $IPT
-t nat -A PREROUTING -p TCP --dport 80 -i $NTINT -m mark --mark 0 -j DNAT --to-destination $IP_PRIVATE:8080
 
 
   
# MARK 0x1 blacklistacls
    $IPT
-t filter -A FORWARD -m mark --mark 0x1 -j REJECT
 
    $IPT
-t nat -A POSTROUTING -m mark ! --mark 0 -j MASQUERADE
 
    echo
"Done."
   
;;
  stop
)
    echo
-n "Flushing kanet firewall's rules: "
        echo
0  > /proc/sys/net/ipv4/ip_forward
 
   
###########################
   
# FLUSH TABLES
   
###########################
    $IPT
-t filter -F
    $IPT
-t nat -F
    $IPT
-t mangle -F
    echo
"Done."
   
;;
 
  status
)
   
# List tables
    echo
    echo
"---------- FILTER TABLE -----------"
    echo
    $IPT
-t filter -L -v
    echo
    echo
"----------   NAT TABLE  -----------"
    echo
    $IPT
-t nat -L -v
    echo
    echo
"----------   MANGLE TABLE  -----------"
    echo
    $IPT
-t mangle -L -v
    echo
   
;;
        restart
|force-reload)
                $0 stop
                $0 start
                echo
"Done."
               
;;
 
       
*)
    echo
"Usage: /etc/init.d/kanet {start|stop|status|restart}"
   
exit 1
   
;;
esac
 
exit 0

On rend le script exécutable et on le programme au démarrage :
chmod +x /etc/init.d/kanet-rules
/etc/init.d/kanet-rules start

update-rc.d kanet-rules defaults

Le serveur Kanet

On édite le fichier /etc/kanet/kanet.conf (au format JSon, attention aux oublis de virgules et autres parenthèses fermantes) et on procède à quelques réglages expliqués ci-dessous :

/*                Server configuration        */

        "SERVER_MODE" : "PROXY",
        "SERVER_URL" : "https://kanet.iut.rdz",
        "SERVER_PORT" : "8181",
        "REDIRECT_SERVER_PORT" : "8080",
        "QUEUE_NUM" : "0",
        "SSL_CERT_FILE" : "/etc/kanet/ssl-kanet.crt",
        "SSL_KEY_FILE"  : "/etc/kanet/ssl-kanet.key",
        "DEBUG" : "1",


SERVER_MODE : "PROXY" : avec ce choix, on force Kanet à n'écouter que sur l'adresse locale 127.0.0.1. Kanet va alors échanger localement en clair (sans ssl) avec le serveur Apache.
L'autre valeur acceptée est "STAND_ALONE" si on choisit de se passer d'Apache. Dans ce cas, Kanet utilisera les fichiers de clé et certificat définis dans les variables SSL_CERT_FILE et SSL_KEY_FILE. (Note : au moment de l'écriture de ces lignes, la présence de ces deux dernières variables est nécessaire, même en mode PROXY où elles ne sont pas utilisées)
SERVER_URL : C'est l'URL du serveur Kanet (doit être résolue depuis le réseau captif) que le serveur présentera à l'utilisateur dans le redirecteur.
SERVER_PORT : C'est le port d'écoute de Kanet sur lequel il reçoit les requêtes http de l'utilisateur (comme /login_cas/ ou encore /www/update.html) . Peut valoir 443 en mode STAND_ALONE.
REDIRECT_SERVER_PORT : C'est le port du serveur de redirection. Quand un utilisateur n'est pas encore authentifié son trafic http est redirigé par IPTable vers ce port du serveur local
DEBUG : "1" : active la trace de sortie pour faciliter la mise au point de la configuration (autre vvaleur autorisée : 0)
      /*                Server behavior        */
        "login_page" : "https://cas.iut-rodez.fr/cas/?service=https://kanet.iut.rdz/login_cas/",
        "captive_portal_page" : "https://kanet.iut.rdz/www/update.html",
        "cas_url" : "https://cas.iut-rodez.fr/cas/",
        "www_path" : "/usr/share/kanet/",
        "module_path" : "/usr/lib",
        "auth_module_name" : "kanet-radiusclient",

login_page : c'est l'URL de la page où l'utilisateur pourra s'authentifier (actuellement pour CAS, il faut écrire en dur le service de retour : ?service=etc). Dans notre exemple, il s'agit de l'URL du serveur CAS avec un paramètre de retour sur l'URL du serveur kanet avec un path sur "/login_cas/" pour obliger Kanet à ouvrir une session (kanet) associée au ticket CAS reçu.
captive_portal_page : c'est l'URL de la page html reçue dans la fenêtre qui doit rester ouverte. C'est elle qui exécute, dans le browser de l'utilisateur, un script javascript notifiant périodiquement le serveur afin qu'il conserve la session active.
cas_url : c'est l'URL du serveur d'authentification CAS.
       /*                open acls       always open       */
        "KANET_ACL_TYPE_OPEN": [
                { "address" : "cas.iut-rodez.fr" },
                { "address" : "www.iut-rodez.fr" },
                { "address" : "cache.iut-rodez.fr" },
                { "address" : "ocsp.tcs.terena.org" },
                { "address" : "ocsp.usertrust.com" }
        ]

Kanet permet (heureusement) de laisser des ACL ouvertes en permanence. Il faut bien sûr penser, par exemple, à laisser l'utilisateur accèder  :
  • à CAS !!! Kanet doit forcément laisser passer le trafic vers le serveur d'authentification sous peine de se "bloquer lui-même",
  • au serveur délivrant la configuration du proxy pour le browser (proxy.pac) le cas échéant, sous peine d'un comportement erratique du navigateur,
  • aux serveurs autorités de certification sous peine de voir des certificats comme ceux obtenus via le CRU non vérifiés et donc une interruption de la transaction par le browser,
  • à tout serveur ne nécessitant pas une authentification (choix politique) comme le serveur web institutionnel de l'organisation par exemple ...


Le serveur Apache

On supprime le vhost par défaut :
a2dissite default

On ajoute des ports d'écoute :
/etc/apache2/ports.conf

NameVirtualHost 192.168.200.1:443
Listen 443
NameVirtualHost 192.168.200.1:8080
Listen 8080
On édite un nouveau vhost apache
vi /etc/apache2/sites-avalaible/kanet


<VirtualHost 192.168.200.1:443>
        SSLEngine On

        SSLCertificateFile /etc/apache2/server.crt
        SSLCertificateKeyFile /etc/apache2/server.key
        SSLVerifyClient none
        SSLProxyEngine On

        Alias /www /usr/share/kanet/

        ProxyPreserveHost On
        ProxyRequests On
        ProxyPass /www  !
        ProxyPass  / http://127.0.0.1:8181/ disablereuse=on retry=0 flushpackets=on
        ProxyPassReverse / http://127.0.0.1/
        ProxyTimeout 3

        <location />
        Allow From All
        </location>


        ErrorLog /var/log/apache2/error.log
        LogLevel warn
        CustomLog /var/log/apache2/access.log combined

</VirtualHost>

<VirtualHost 192.168.200.1:8080>
        RewriteEngine On
        RedirectMatch .* https://cas.iut-rodez.fr/cas/login/?service=https://kanet.iut.rdz/login_cas/

        ErrorLog /var/log/apache2/error.log
        LogLevel warn
        CustomLog /var/log/apache2/access.log combined

</VirtualHost>

Explication succinte :

Il y a deux virtual hosts Apache.

Celui sur le port 8080 (le deuxième dans cet exemple) est chargé de recevoir la requête http initiale émise par l'utilisateur vers le web et déroutée par IPTable. Il renvoie au browser une redirection vers CAS avec un paramètre service : "quand tu reviens de CAS, va ensuite sur https://mon_serveur_kanet/login_cas/".

Le premier virtual host de l'exemple, qui écoute sur le port 443, est justement chargé de traiter cette requête en la proxifiant localement sur le port 8181. Il traite aussi toute autre requête http proxifiée vers kanet, comme les services REST, mais laisse Apache servir les pages sous l'emplacement /www, comme update.html.

On n'oublie pas d'activer ce nouveau vhost
a2ensite kanet

Démarrage du service

On lance Apache :
/etc/init.d/apache2 restart

Et  Kanet :
/etc/init.d/kanet start


Note : Kanet peut être lancé manuellement (commande : kanet) afin de lire les sorties directement dans la console. Pratique par exemple pour vérifier la validité de la conf JSON ou l'état du trafic pendant la mise au point.

Kanet et filtrage web : voir Kanet + Squid

Merci à Cyrille pour le temps passé à débugger ma configuration.

Une configuration détaillée de kanet pour Shibboleth et Radius sous Fedora a été écrite par Xavier Marty de l'Université de Toulouse 1 Capitole. Avec son accord, elle est disponible ici.

TODO  : Ajouter détails sur l'éclatement du log et le log rotate






Pff