lid's stuff

Nantes Wifi Public: OpenVPN over HTTPS?

Article basé sur:

https://snikt.net/blog/2016/12/01/openvpn-over-https/

Comme en ce moment on s'amuse, chez FAImaison, avec le nouveau service de WiFi gratuit de la ville de Nantes, qui, s'il est certes sympathique, limite beaucoup l'usage d'Internet (pleins de ports bloqués: SSH, VPN, IRC, Newsgroups, P2P, etc - mais, et c'est un bon point, pas Tor. En fait on ferait mieux de parler de ports autorisés: SMTP(S), POP3(S), IMAP(S), HTTP(S), etc), et que les premiers tests ont montré que, à première vue, il est impossible de se connecter à un VPN, je me suis demandé si en "dissimulant" OpenVPN derrière un site HTTPS classique, ça pouvait passer. Spoiler: non, ça marche pas directement, c'est un peu plus "tricky". Par contre ça fonctionne sur des réseaux limitants mais qui ne font pas passer tout le trafic par un proxy transparent (Squid dans le cas de Nantes Wifi public)

Prérequis

  • Un serveur ouaibe (nginx, papache2, lighttpd) ou notre bon vieux HAProxy
  • Un certificat (let's encrypt par exemple)
  • OpenVPN (orly?)
  • Une table à une terrasse de café, du soleil, et un bon café, le tout à portée d'un point d'accès Wifi Nantes Public.

Fonctionnement

Notre serveur OpenVPN écoutera sur le port 443, notre serveur Web (ou HAProxy) écoutera lui, en tls, sur localhost:port_au_choix

OpenVPN lui relaiera le trafic via la directive port-share IP PORT

Un petit schéma ne coûtant rien, voici mon setup avec HAProxy:

schema moche - je sais pas dessiner

Oui, je ne sais pas dessiner. Non, je n'ai pas de mainframe IBM ZSeries chez moi (snif).

Configuration

MachinBox© - si on le fait chez soi, pas sur un serveur dédié

On activera les règles de NAT/PAT suivantes sur notre machinbox©:

  • Port 80 en entrée sur le port 80 de l'IP de notre serveur VPN/HAProxy. HAProxy utilisera la directive redirect scheme https code 301 if !{ ssl_fc } pour rediriger le trafic HTTP vers HTTPS, c'est plus propre et nous sommes en 2017.
  • Port 443 en entrée sur le port 443 de l'IP de notre serveur VPN/HAProxy.

Haproxy et Let's Encrypt

Tout d'abord, concernant HAProxy et Let's Encrypt, on va partir sur la configuration décrite dans un précédent post: Let's Encrypt et HAProxy.

Une fois que cette configuration est opérationnelle et que les certificats ont été générés, on va modifier la ligne de la configuration (/etc/haproxy/haproxy.cfg):

bind *:443 ssl crt /etc/haproxy/certs/ no-sslv3 strict-sni

Par (ici on utilisera le port 8443):

bind 127.0.0.1:8443 ssl crt /etc/haproxy/certs/ no-sslv3 strict-sni

et relancer HAProxy: $ sudo systemctl reload haproxy

On aura aussi, préalablement, installé nginx, lighttpd ou apache2 (ici dans une VM), et défini une backend par défaut (ou pas) d'HAProxy, par exemple:

frontend ma_frontend
    bind *:80
    bind 127.0.0.1:8443 ssl crt /etc/haproxy/certs/ no-sslv3 strict-sni
    … blabla frontend, ACLs, etc …
    default_backend my_backend

backend my_backend
    balance leastconn
    option httpclose
    option forwardfor
    server mon_serveur adresse_ip:port check
    server mon_serveur_2 adresse_ip:port check

OpenVPN

Serveur

On partira du setup décrit dans le post Se faire son VPN Perso.

Sauf que… Nous allons modifier:

  • Le port sur lequel écoute OpenVPN
  • Le protocole de communication utilisé (tcp au lieu d'udp)
  • Et ajouter 3 lignes de configuration pour prendre en charge la redirection du trafic HTTPS "normal" vers notre frontend HAProxy qui écoute donc sur 127.0.0.1:8443 ainsi que les algorithmes de chiffrement TLS nécessaires.

Ce qui nous donne (je liste juste les modifications par rapport à la configuration décrite dans le post Se faire son VPN Perso.):

port 443
proto tcp-server
… reste de la configuration …
dev tun
port-share 127.0.0.1 8443
… reste de la configuration …
cipher AES-256-CBC
auth SHA512
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA
… atchoum, fin de la configuration …

et on relancera notre serveur openvpn, ici, si le fichier de configuration est /etc/openvpn/server.conf:

$ sudo systemctl restart openvpn@server

Client

Pour la configuration du client, c'est nettement plus simple. Toujours en se basant sur la configuration du client décrite dans le post Se faire son VPN Perso, on modifiera:

  • le protocole utilisé: TCP au lieu d'UDP
  • on ajoutera une directive pour qu'il prenne en compte le tunnel HTTPS

Ce qui nous donne:

client
proto tcp-client
… reste de la config …
cipher AES-256-CBC
auth SHA512
… reste de la config …

Test

On va donc tester de se rendre à l'adresse de notre site Web avec notre navigateur favori (de préférence de type panda roux, suivez mon regard):

https://mon.site.web

On devrait normalement arriver sur la page web de notre serveur (par exemple la page "It works" ou autre par défaut - à vous de mettre du contenu derrière :p)

Et si on se connecte avec openvpn et notre fichier de configuration client, on devrait être connecté à notre VPN :)

Mais ça marche pas avec le Wifi Public Nantais!!

Eh bin ouais. En fait, si on regarde notre route par défaut lorsqu'on est connecté sur le Wifi Nantais, et qu'on scanne les ports de la passerelle en question via par exemple, l'utilitaire nmap, on va se rendre compte que plusieurs ports sont ouverts sur cette passerelle, et notamment:

8080 Squid
8081 Squid
… etc

C'est à dire un proxy HTTP potentiellement filtrant qui refuse de renvoyer, ou altère d'une façon ou d'une autre le premier paquet TLS envoyé par notre serveur dans le tunnel de notre VPN, qu'il soit encapsulé dans HTTPS ou pas, ce qui, bien évidemment, viande le client qui refuse de continuer à parler à ce malpoli.

Maintenant, on sait qu'on a un proxy Squid qui écoute sur l'IP de la passerelle sur plusieurs ports. On va donc dire à notre client de se servir, par exemple, de l'IP de cette passerelle sur le port 8080 en tant que proxy HTTP. Imaginons qu'ip route show nous permette de déterminer que notre passerelle est 10.240.160.1. On va donc rajouter à la configuration de notre client la directive:

http-proxy 10.240.160.1 8080

Si on se reconnecte à notre VPN, cette fois-ci, ça passe! Tout ça pour retrouver un Internet propre, non filtré, et un réseau de confiance… groumph!

Maintenant, prochain test:

  • me créer un enregistrement DNS A ou CNAME du genre: monvpnamoi.lidstah.info IN CNAME chezmoi.lidstah.info.
  • Utiliser l'ACL HaProxy acl is_vpn if hdr(host) -i monvpnamoi.lidstah.info
  • Utiliser une backend TCP si cette ACL est vérifiée: use_backend my_vpn if is_vpn

Et définir une backend tcp comme suit:

backend my_vpn
    mode tcp
    balance leastconn
    server mon_vpn ip_serveur_vpn:port check

Avec par exemple une VM qui fait tourner openvpn sur ip_serveur_vpn:port

Et ensuite utiliser ça comme proxy http:

http-proxy monvpnamoi.lidstah.info 80

Dans la config' de mon client VPN. Mais bon, ça, je testerai ce week-end :)


Tagged under: sysadmin, haproxy, openvpn, nantes, wifi