Il existe trois manière conventionnelles de monter un VPN. La première concerne l'utilisation de ssh comme base de chiffrement du flux allié à une connexion via le protocole point à point (PPP).
Nous allons encapsuler un tunnel capable de transporter du TCP/IP ou de l'UDP/IP par dessus une pile qui est elle-même composée par TCP/IP.
Représentation de l'objectif :
------------------------------ | Charge (telnet, http, etc) | ------------------------------ | TCP | ------------------------------ | IP | ------------------------------ | PPP | ------------------------------ | SSH | ------------------------------ | TCP | ------------------------------ | IP | ------------------------------
On peut clairement constater le double usage de TCP/IP.
Nous allons vérifier que nous disposons des outils nécessaires pour ce travail, que ce soit au niveau du noyau ou logiciel. En effet, il faut avoir activé le support du protocol PPP dans le noyau, soit directement, soit par module. Concernant les logiciels, il est nécessaire d'installer pppd ainsi que le client ssh.
Nous voulons établir un tunnel VPN selon le schéma suivant :
Pour les besoins du TP, je vais réutiliser Netkit qui est, je dois le dire, un formidable outil.
Petit rappel sur la procédure d'installation, vous pouvez consulter mes notes ou directement la documentation officielle en ligne.
Avant de démarrer les hôtes virtuels, il est important de mettre en place l'organisation du réseau. Pour cela, nous allons utiliser deux hôtes (hostA et hostB), ainsi qu'un routeur intermédiaire.
Le fichier lab.conf :
adminbdd labo-vpn # cat lab.conf hostA[0]="networkA" hostB[0]="networkB" router[0]="networkA" router[1]="networkB"
adminbdd labo-vpn # cat hostA.startup ifconfig eth0 195.0.0.10 netmask 255.255.255.0 broadcast 195.0.0.255 up route add default gw 195.0.0.1 mknod /dev/ppp c 108 0 adminbdd labo-vpn # cat hostB.startup ifconfig eth0 196.0.0.10 netmask 255.255.255.0 broadcast 196.0.0.255 up route add default gw 196.0.0.1 mknod /dev/ppp c 108 0 adminbdd labo-vpn # cat router.startup ifconfig eth0 195.0.0.1 up ifconfig eth1 196.0.0.1 up
Démarrage du laboratoire :
adminbdd labo-vpn # lstart ======================== Starting lab =========================== Lab directory: /var/opt/netkit/labo-vpn Version: 1.0 Author: Vanvincq Clément Email: vanvincq.clement@gmail.com Web: http://www.eof.eu.org/ Description: Exercice VPN par SSH ================================================================= Starting "hostA"... Starting "hostB"... Starting "router"... The lab has been started. =================================================================
Au cas où, on vérifie que tout fonctionne parfaitement :
hostA:~# ifconfig eth0 eth0 Link encap:Ethernet HWaddr 1e:b4:f2:49:63:5f inet addr:195.0.0.10 Bcast:195.0.0.255 Mask:255.255.255.0 inet6 addr: fe80::1cb4:f2ff:fe49:635f/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:11 errors:0 dropped:0 overruns:0 frame:0 TX packets:11 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:692 (692.0 B) TX bytes:846 (846.0 B) Interrupt:5 hostA:~# ping -c3 196.0.0.10 PING 196.0.0.10 (196.0.0.10) 56(84) bytes of data. 64 bytes from 196.0.0.10: icmp_seq=1 ttl=63 time=0.729 ms 64 bytes from 196.0.0.10: icmp_seq=2 ttl=63 time=0.288 ms 64 bytes from 196.0.0.10: icmp_seq=3 ttl=63 time=0.372 ms --- 196.0.0.10 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1998ms rtt min/avg/max/mdev = 0.288/0.463/0.729/0.191 ms hostB:~# ifconfig eth0 eth0 Link encap:Ethernet HWaddr 72:e1:04:ca:38:92 inet addr:196.0.0.10 Bcast:196.0.0.255 Mask:255.255.255.0 inet6 addr: fe80::70e1:4ff:feca:3892/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:11 errors:0 dropped:0 overruns:0 frame:0 TX packets:11 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:692 (692.0 B) TX bytes:846 (846.0 B) Interrupt:5 hostB:~# ping -c3 195.0.0.10 PING 195.0.0.10 (195.0.0.10) 56(84) bytes of data. 64 bytes from 195.0.0.10: icmp_seq=1 ttl=63 time=0.312 ms 64 bytes from 195.0.0.10: icmp_seq=2 ttl=63 time=0.236 ms 64 bytes from 195.0.0.10: icmp_seq=3 ttl=63 time=0.353 ms --- 195.0.0.10 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1998ms rtt min/avg/max/mdev = 0.236/0.300/0.353/0.050 m
Maintenant, créons un utilisateur sur le deuxième hôte :
hostB:/hosthome# adduser vpn Adding user `vpn' ... Adding new group `vpn' (1001) ... Adding new user `vpn' (1001) with group `vpn' ... Creating home directory `/home/vpn' ... Copying files from `/etc/skel' ... Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully Changing the user information for vpn Enter the new value, or press ENTER for the default Full Name []: Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n] Y hostB:~# /etc/init.d/ssh start Starting OpenBSD Secure Shell server: sshd
hostA:~# ssh -l vpn 196.0.0.10 The authenticity of host '196.0.0.10 (196.0.0.10)' can't be established. RSA key fingerprint is 53:d4:13:1a:f0:a3:e9:43:6b:04:6c:d0:bc:63:10:29. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '196.0.0.10' (RSA) to the list of known hosts. vpn@196.0.0.10's password: vpn@hostB:~$
Bien, tout est prêt pour initier la connexion PPP. On va ajouter une clef RSA pour simplifier l'authentification SSH.
hostA:~/.ssh# ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): /root/.ssh/id_rsa already exists. Overwrite (y/n)? y Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: c0:e4:0a:f1:6e:0e:6b:9c:99:62:b0:52:76:05:87:30 root@hostA The key's randomart image is: +--[ RSA 2048]----+ | E...o | | +.* | | . . = | | o o . | |. + = S | |.= X | |+.B . | |oo | | | +-----------------+ hostA:~/.ssh# ls id_rsa id_rsa.pub known_hosts hostA:~/.ssh# ssh vpn@196.0.0.10 "mkdir -p .ssh" vpn@196.0.0.10's password: hostA:~/.ssh# cat ./id_rsa.pub | ssh vpn@196.0.0.10 "cat >> .ssh/authorized_keys" hostA:~/.ssh# ssh-agent hostA:~/.ssh# ssh-add Enter passphrase for /root/.ssh/id_rsa: Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa) hostA:~/.ssh# ssh-add -l 2048 c0:e4:0a:f1:6e:0e:6b:9c:99:62:b0:52:76:05:87:30 /root/.ssh/id_rsa (RSA) hostA:~/.ssh# ssh vpn@196.0.0.10 hostname hostB
Il reste une dernière chose à installer : la commande sudo. Normalement, je ne devrais pas à avoir le faire mais dans ma version de netkit, il y a un bug référencé qui empêche la prise en compte de la directive USE_SUDO=yes dans le fichier /$HOME_NETKIT/netkit.conf. Pour cela j'ai téléchargé le paquet binaire sudo pour la version 4 de Debian (sinon, il risquerait d'y avoir un problème de dépendance avec glibc. Pour importer ce paquet directement dans les machines virtuelles, il suffit de le placer dans le répertoire /home de la machine hôte. Ensuite, rendez-vous dans le /hosthome des machines virtuelles pour y retrouver vos documents ;)
hostA:/hosthome# dpkg -i sudo_1.7.9-1_i386.deb Selecting previously deselected package sudo. (Reading database ... 31970 files and directories currently installed.) Unpacking sudo (from sudo_1.7.9-1_i386.deb) ... Setting up sudo (1.7.9-1) ... Processing triggers for man-db ... hostB:/hosthome# dpkg -i sudo_1.7.9-1_i386.deb Selecting previously deselected package sudo. (Reading database ... 31970 files and directories currently installed.) Unpacking sudo (from sudo_1.7.9-1_i386.deb) ... Setting up sudo (1.7.9-1) ... Processing triggers for man-db ...
Configuration du fichier /etc/sudoers pour l'utilisateur vpn :
hostB:/home/vpn# visudo [...] # Ajoutons cette ligne vpn ALL=NOPASSWD: /usr/sbin/pppd
Ok, tout est prêt pour le grand test :)
hostA:~# pppd updetach noauth debug pty "ssh -l vpn -t 196.0.0.10 sudo /usr/sbin/pppd nodetach notty noauth" ipparam vpn 192.168.0.1:192.168.0.2 using channel 3 Using interface ppp0 Connect: ppp0 <--> /dev/pts/0 rcvd [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x5254a39a> <pcomp> <accomp>] sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0xb2ebb5fa> <pcomp> <accomp>] sent [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0x5254a39a> <pcomp> <accomp>] rcvd [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0xb2ebb5fa> <pcomp> <accomp>] sent [LCP EchoReq id=0x0 magic=0xb2ebb5fa] sent [CCP ConfReq id=0x1 <deflate 15> <deflate(old#) 15> <bsd v1 15>] sent [IPCP ConfReq id=0x1 <compress VJ 0f 01> <addr 192.168.0.1>] rcvd [LCP EchoReq id=0x0 magic=0x5254a39a] sent [LCP EchoRep id=0x0 magic=0xb2ebb5fa] rcvd [CCP ConfReq id=0x1 <deflate 15> <deflate(old#) 15> <bsd v1 15>] sent [CCP ConfAck id=0x1 <deflate 15> <deflate(old#) 15> <bsd v1 15>] rcvd [IPCP ConfReq id=0x1 <compress VJ 0f 01> <addr 0.0.0.0>] sent [IPCP ConfNak id=0x1 <addr 192.168.0.2>] rcvd [LCP EchoRep id=0x0 magic=0x5254a39a] rcvd [CCP ConfAck id=0x1 <deflate 15> <deflate(old#) 15> <bsd v1 15>] Deflate (15) compression enabled rcvd [IPCP ConfAck id=0x1 <compress VJ 0f 01> <addr 192.168.0.1>] rcvd [IPCP ConfReq id=0x2 <compress VJ 0f 01> <addr 192.168.0.2>] sent [IPCP ConfAck id=0x2 <compress VJ 0f 01> <addr 192.168.0.2>] Cannot determine ethernet address for proxy ARP local IP address 192.168.0.1 remote IP address 192.168.0.2
Bien, cela fonctionne :) Vérifions quelques détails au cas où !
hostA:~# ifconfig eth0 Link encap:Ethernet HWaddr 1e:b4:f2:49:63:5f inet addr:195.0.0.10 Bcast:195.0.0.255 Mask:255.255.255.0 inet6 addr: fe80::1cb4:f2ff:fe49:635f/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:369 errors:0 dropped:0 overruns:0 frame:0 TX packets:419 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:52240 (51.0 KiB) TX bytes:58850 (57.4 KiB) Interrupt:5 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:460 (460.0 B) TX bytes:460 (460.0 B) ppp0 Link encap:Point-to-Point Protocol inet addr:192.168.0.1 P-t-P:192.168.0.2 Mask:255.255.255.255 UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1 RX packets:5 errors:0 dropped:0 overruns:0 frame:0 TX packets:5 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:3 RX bytes:78 (78.0 B) TX bytes:72 (72.0 B)
hostA:~# ping -c 3 192.168.0.2 PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data. 64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=5.84 ms 64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=3.25 ms 64 bytes from 192.168.0.2: icmp_seq=3 ttl=64 time=3.72 ms --- 192.168.0.2 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2023ms rtt min/avg/max/mdev = 3.259/4.276/5.842/1.125 ms
Yeah! it works! Maintenant quelques explication sur la commande :
pppd debug updetach noauth
Il se peut que la commande pppd demande le chemin complet de l’application. Dans ce cas, utilisez la commande whereis pour compléter l’information. Les trois mots suivants sont des options. L’option debug n’est présente que pour fournir des renseignements complémentaires au cas où votre connexion ne s’effectuerait pas, updetach permet de détacherpppd du tty où il a été lancé pour le transformer en daemon. Pour terminer, noaut demande à ce que pppd ne se préoccupe pas de la partie authentification. Celle-ci, comme nous l’avons déjà dit, reviendra à ssh.
pty "ssh -l login -t AdresseDistante
L’option pty permet ici de passer les commandes suivantes au shell distant que nous venons d’ouvrir. L’option -t de ssh, quant à elle, force l’allocation du pseudo-tty sur la machine distante. C’est en quelque sorte l’équivalent de ce que nous venons de voir pour pppd avec pty.
pppd noauth 192.168.254.254:192.168.253.253"
Cette dernière ligne attribue une adresse privée virtuelle à chacun des bouts du réseau. Vous pouvez faire communiquer vos machines de l’une vers l’autre sans aucun souci. Félicitations, vous venez de créer votre premier VPN.
L’IP_FORWARDING est un drapeau qui dit au noyau linux s’il doit laisser passer les paquets à travers la machine ou si, au contraire, il doit les stopper. Par défaut, dans les distributions actuelles, il est initialisé à 0 à chaque démarrage. Le script suivant vous permet de l’initialiser à 1 si vous souhaitez qu’une des deux machines, ou les deux, servent de passerelle pour d’autres machines de vos réseaux, ce qui permet non plus uniquement la communication d’un poste à un autre, mais également d’un réseau à un autre.
#!/bin/sh echo "Mise en place des règles de transfert IP" echo 1 > /proc/sys/net/ipv4/ip_forward echo -n "/proc/sys/net/ipv4/ip_forward: " cat /proc/sys/net/ipv4/ip_forward for forwarding in /proc/sys/net/ipv4/conf/*/forwarding do echo -n "$forwarding: "; interface=‘dirname $forwarding‘ interface=‘basename $interface‘ case "$interface" in ppp*|eth1) # liste des interfaces où le transfert # doit être activé echo 1 > $forwarding ;; *) # On désactive les interfaces qui ne nécessitent # pas le transfert. echo 0 > $forwarding ;; esac cat $forwarding done
Le serveur SSH est livré avec son fichier de configuration par défaut, nommé sshd_config. Par défaut, celui-ci écoute sur le port 22, nous allons le modifier pour qu’il écoute sur le port 9876. Ceci a pour résultat deux choses :
les robots qui scannent le port 22 pour trouver un ssh faillible n’embêteront pas le serveur
les logs d’authentification ne concerneront normalement que les tentatives d’accès au vpn.
# vpn/etc # Configuration spécifique du port Port 9876 PidFile /var/run/sshd_vpn.pid HostKey /etc/ssh/ssh_host_key HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_dsa_key ServerKeyBits 768 LoginGraceTime 600 KeyRegenerationInterval 3600 # Configuration des niveaux des journaux SyslogFacility AUTH LogLevel INFO RSAAuthentication yes AllowUsers sshvpn # Restrictions # IgnoreRhosts yes IgnoreUserKnownHosts yes PermitRootLogin no StrictModes yes PasswordAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no RhostsAuthentication no RhostsRSAAuthentication no X11Forwarding no PrintMotd no KeepAlive yes
Dès lors que vos essais initiaux auront été fructueux, vous désirerez sûrement automatiser votre vpn. Pour ce faire, il est utile et propre de créer un fichier de configuration qui contiendra les variables nécessaires à la création de votre tunnel vpn :
# VPN1 Configuration File # /opt/ssh-vpn/etc/vpn1 # Les réseaux sont connectés d’une part et d’autre, # suite à la commande route client_network=192.168.2.0/24 server_network=192.168.1.0/24 # Désirez vous des informations de debug ? client_debug="no" server_debug="yes" # Prenez des IPs différentes pour chaque VPN nécessaire. server_ppp_ip=192.168.254.254 client_ppp_ip=192.168.254.253 # Y a t-il une authentification PPP requise ? client_require_pap="yes" server_require_pap="yes" client_require_chap="no" server_require_chap="no" # Besoin d’arguments pppd non-standards ? Mettez-les ici. #client_pppd_args="usepeerdns" #server_pppd_args="proxyarp" # Besoin d’arguments ssh supplémentaires ? Mettez les ici #client_ssh_args="-C" #server_ssh_args=""