IPSec net to host

On voit habituellement des liens IPSec net-net, reliant deux réseaux, ou host-net, c’est-à-dire un hôte établissant une liaison IPSec vers un réseau. Dans mon cas, j’ai besoin qu’un hôte de mon réseau interne puisse contacter un hôte spécifique traînant sur Internet, et cela à travers un canal sécurisé. Étonnamment cette configuration est assez rare pour que la documentation relative à sa mise en place soit inexistante pour le moins, mais pas impossible 🙂

On appelle souvent les connexions IPSec de type host to net roadwarrior. Le cas d’usage fréquent est celui du télétravail, où un usager a besoin d’accéder à des ressources se trouvant dans le réseau interne de sa boîte. On observe alors les différences suivantes par rapport à une connexion reliant deux sites :

  • l’initiateur est l’hôte
  • l’initiateur ne connait pas son adresse locale (IP non fixe)
  • le endpoint côté réseau interne accepte les connexions depuis toutes les IP

Dans cette situation, il est possible de spécifier une IP privée, qui va permettre au endpoint côté réseau (et donc de manière transitive à tous le réseau) de pouvoir contacter l’hôte. C’est en tirant parti de cette fonctionnalité et en utilisant une configuration de type net-net que je vais pouvoir parvenir à mes fins.

Ci-dessous la configuration que j’utilise (je n’ai mis que l’essentiel, en mettant en évidence les paramètres clés). J’utilise IKEv2 qui est simplement the way to go, ce protocole étant mieux que l’ancestral IKEv1 sur tous les plans. Je ne suis donc pas sur que cela puisse marcher en IKEv1.

conn uk-endpoint
        auto=route
        left=198.51.100.150
        leftid="C=FR, O=Kveer, OU=Kveer IPSec Services, CN=IPSec-Endpoint"
        right=203.0.113.60
        rightid="C=FR, O=Kveer, OU=Kveer IPSec Services, CN=UK-Endpoint"
        leftsubnet=192.168.4.0/24
        rightsubnet=100.64.10.1/32[tcp]
        rightsourceip=100.64.10.1
        keyexchange=ikev2
        reauth=no
        ike=aes128-sha1-modp2048!
        esp=aes128-sha1-modp2048!
        type=tunnel
        compress=yes
conn home
        auto=route
        left=203.0.113.60
        leftid="C=FR, O=Kveer, OU=Kveer IPSec Services, CN=UK-Endpoint"
        right=198.51.100.150
        rightid="C=FR, O=Kveer, OU=Kveer IPSec Services, CN=IPSec-Endpoint"
        rightsubnet=192.168.4.0/24
        leftsubnet=100.64.10.1/32
        leftsourceip=100.64.10.1
        keyexchange=ikev2
        reauth=no
        ike=aes128-sha1-modp2048!
        esp=aes128-sha1-modp2048!
        type=tunnel
        compress=yes

Une fois les deux endpoints configurés :

  • le tunnel va pouvoir être établi d’un côté comme de l’autre
  • les hôtes du réseau interne vont pouvoir contacter le serveur standalone sur son IP privée 100.64.10.1
  • et bien entendu, le serveur standalone va pouvoir se connecter au réseau interne

Se connecter à TigerVPN avec Linux

J’ai profité d’une offre promotionnelle proposée par TigerVPN pour leur service de VPN à vie pour 30€. C’est toujours pratique de pouvoir changer d’IP en cas de route réseau défectueuse ou lorsque l’IP du FAI est banni par le service qu’on essaye d’atteindre (les restriction géographique par exemple tombent dans ce cas).

Bref, Tiger et la plupart de ses concurrents proposent des VPN clé-en-main pour plateforme Windows et mobile. On a donc souvent du IPSec/L2TP, OpenVPN, ou parfois l’utilisation d’un client maison (mais c’est vraiment pas génial sur mobile, du fait de la mauvaise intégration d’un point de vue de la continuité du service et de la consommation batterie). Sur ces plateformes, ça marche mais on ne trouve aucune informations techniques permettant de s’y connecter proprement depuis un client Linux.

Voici ma configuration, après pas mal d’essais, pour se connecter à TigerVPN en utilisant Strongswan sous Gentoo.

Tout d’abord, on aura besoin des paquets suivants :

emerge va xl2tpd strongswan

La configuration de la partie IPSec. Elle établit un tunnel entre le Linux et TigerVPN, uniquement pour les paquets udp sur le port 1701. C’est le port qu’utilise par défaut le protocole L2TP.

conn tigervpn
        add=route
        type=transport
        right=xxx.tigervpn.com
        esp=aes256-sha1!
        ike=aes256-sha1-modp1024!
        rekey=no
        keyingtries=1
        leftprotoport=udp/1701
        rightprotoport=udp/1701
        leftid=192.168.12.14
        leftsubnet=192.168.12.14/32
        rightid=%any
        leftcert=
        leftca=
        rightca=
        leftauth=psk
        rightauth=psk
        keyexchange=ikev1
        mobike=yes
192.168.12.14 %any : PSK "secret-partagé-tigervpn"

Maintenant, on passe à la configuration de la couche L2TP :

[lac tigervpn]
lns = xxx.tigervpn.com
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
require authentication = yes

Puis la configuration de la couche PPP :

ipcp-accept-local
ipcp-accept-remote
refuse-eap
require-mschap-v2
noccp
noauth
idle 1800
#crtscts
mtu 1410
mru 1410
nodefaultroute
lock
proxyarp
silent
name your-username
password your-very-secret-password

On vérifiera que les fichiers contenant des mot de passes ne sont accessibles que par root !

Maintenant, on peut démarrer les différents services :

/etc/init.d/ipsec start
/etc/init.d/xl2tpd start
sleep 3
echo "c tigervpn" > /var/run/xl2tpd/l2tp-control

Le sleep s’assure que les deux daemons soient bien initialisées.

La commande echo demande à xl2tpd de se connecter au lac nommé tigervpn. Ce lac a pour LNS xxx.tigervpn.com, lequel doit passer en IPSec.

Si tout a bien fonctionné, une nouvelle interface pppX est visible. Il n’y aura plus qu’à ajouter les différentes routes vers les destinations que l’on souhaite faire passer dans le VPN.

Enjoy !

Monter un tunnel IPSec sous Linux

Ce billet détaille comment monter un tunnel IPSec sous Linux. C’est à mon sens un must have, principalement parce qu’IPSec est une merde ignoble sous Linux.
Mais avant de procéder plus avant, une question se pose.

Pourquoi IPSec ?

Actuellement je souhaite relier :

  • plusieurs serveurs sur Internet
  • plusieurs réseau locaux (celui du bureau et ceux des machines virtuelles derrières le routeur qui détient l’IP publique)

Voici mes possibilités pour réaliser ce « gros » réseau :

  • créer plein de règles nat sur chaque routeurs.
    • c’est pénible à maintenir
    • oblige à reconfigurer les services pour n’utiliser que certaines plages de ports, et sans chevauchement d’une machine/vm à l’autre
    • oblige à avoir une feuille avec la table de mapping et utiliser des ports non standards
      Pas géniale comme solution, et les tuyaux ne sont pas sécurisés.
      On peut alors reconfigurer tous les services pour protéger chaque flux, mais la manière de faire et la possibilité dépendent du service. Désormais on a la plupart des tuyaux qui sont sécurisés et encore plus de maintenance.
  • mettre en place OpenVPN qui répond entièrement à la problématique, mais :
    • il est architecturé en étoile (1 serveur, plusieurs clients). On peut aussi installer OpenVPN sur chaque routeur en mode serveur, mais c’est pas mal de configuration.
    • il fonctionne en faisant le transport sur la couche applicative du modèle OSI (les paquets sont encapsulé dans un flux SSL sur du TCP ou UDP), cela induit un peu d’overhead
      C’est la solution qui est actuellement en place chez moi.

Par rapport à OpenVPN, voici les avantages d’IPSec :

  • c’est du P2P, il n’y a pas de notion « serveur », les routeurs se connectent donc en direct
  • comme OpenVPN, la communication entre les 2 pairs est chiffrée
  • il est kernel-space sous Linux et Windows, il est donc moins lourd qu’OpenVPN et ne nécessite aucune installation sous Windows
  • son intégration aux protocoles IPs lui permet d’avoir un overhead plus faible qu’avec OpenVPN, donc une bande passante plus large
  • les tunnels d’OpenVPN semblent saturer vite vers 10Mbps chez moi

Quelle implémentation d’IPSec ?

C’est une question qui ne se pose que pour le monde Unix. Avoir le choix c’est bien, mais dans le cas d’IPSec, c’est un peu compliqué. Côté logiciel, il y a eu FreeSwan, puis OpenSwan, puis StrongSwan ; côté noyau également, il a existé plusieurs implémentations : klips et netkey.
Aujourd’hui, j’ai jeté mon dévolu sur strongswan. Klips n’existe plus et les autres logiciels ne sont plus maintenus depuis plusieurs années, c’est donc quasiment un choix par défaut, mais également pour la négociation par certificats que strongswan est le seul à proposer (et que je trouve beaucoup plus simple à configurer que le Pre-Shared Key).

La conf !

Elle est très simple. Voici un exemple fonctionnel ci-dessous qui utilise l’authentification mutuelle par certificat, pour le détail: RTFM, ce dernier est plutôt à jour et bien réalisé.
Je ne détaille pas comment générer les certificats, ce n’est pas le but du billet, et puis j’ai déjà traité ça ici.

config setup
cachecrls=yes
# uniqueids = no

# Add connections here.
conn %default
auto=start
compress=no # ne fonctionne pas
dpdaction=restart
esp=aes128-sha1!
ike=aes128-sha1-modp2048,aes128-sha1-modp1024!
rightallowany=yes
left=2001:41d0:fe1c:1300:20c:29ff:fe99:fbf
#left=%any
leftauth=pubkey
rightauth=pubkey
leftid="C=FR, O=Kveer, OU=Kveer IPSec Services, CN=Tefnout"
leftca="C=FR, O=Kveer, OU=Kveer IPSec Services, CN=Kveer IPSec CA"
rightca=%same
leftcert=tefnout.crt
leftfirewall=no
mobike=no
keyexchange=ikev2

conn illidan
right=illidan.kveer.fr
rightid="C=FR, O=Kveer, OU=Kveer IPSec Services, CN=Illidan"
leftsubnet=192.168.3.0/24
rightsubnet=192.168.14.128/27
# les règles iptables à ajouter.
iptables -A INPUT -p udp -m multiport --dport isakmp,ipsec-nat-t -m comment --comment ipsec -j ACCEPT
iptables -A INPUT -p esp -j ACCEPT
iptables -t nat -I POSTROUTING 1 -m policy --dir out --pol ipsec -j ACCEPT

La dernière règle iptables est à ne pas oublier si l’on souhaite faire fonctionner le tunnel pour les routeurs eux-mêmes. Dans le cas d’un tunnel IPv4, ça ne marchera pas, dans le cas d’un tunnel IPv6, le kernel va générer un Oops (la règle est obligatoire sous peine de non-sens, mais cela n’autorise pas le kernel à planter, c’est bien un bug, en attente de correction)