Sécuriser le trafic réseau de ses containers Docker à travers un VPN

Sécuriser le trafic réseau de ses containers Docker à travers un VPN

Un VPN ? Mais qu'est-ce donc ? Et qu'est-ce qu'on peut en faire ? Avant de rentrer dans le vif du sujet et d'en mettre un en place, je vais d'abord essayer de vous en expliquer l'utilité et le fonctionnement général.

VPN est l'acronyme de Virtual Private Network, autrement dit Réseau Privé Virtuel. Il s'agit d'un système permettant de créer un lien direct, appelé tunnel, entre deux appareils (ordinateurs, smartphones, serveurs, ...) géographiquement éloignés et connectés physiquement sur des réseaux distincts, tout en isolant les échanges du reste du trafic réseau.

"Affirmer que vous vous moquez du droit à la vie privée parce que vous n'avez rien à cacher revient à dire que vous n'en avez rien à faire de la liberté d'expression parce que vous n'avez rien à dire." Edward Snowden

Il existe plusieurs raisons d'avoir recours à un VPN : anonymiser sa navigation sur Internet, pouvoir accéder librement à des ressources non disponibles là où on se trouve, ou à des ressources privées, que ce soit d'entreprise ou bien chez vous, sans devoir ouvrir le réseau sur Internet.

Dans notre cas, suite à la mise en place de l'automatisation du téléchargement de vos séries et films, un VPN permettra d'anonymiser les téléchargements et d'éviter d'avoir une mauvaise surprise en recevant un mail de la part d’HADOPI. Nous allons donc installer un container qui fera office de VPN client en se connectant à un fournisseur VPN proposant ses services dans divers pays.

L'important lors du choix d'un fournisseur VPN est le nombre de serveurs et de pays auxquels il est possible de se connecter, le fait qu'il respecte votre vie privée et n'enregistre pas les connexions et/ou le trafic, le nombre de périphériques pouvant se connecter et bien entendu le prix (mais après tout, la sécurité de notre vie privée et de nos données personnelles a-t-elle un prix ?).
Il y a régulièrement des prix pour des abonnements chez des fournisseurs VPN répondant à tous ces critères : VPNSecure, IvacyVPN, Windscribe ... Personnellement, j'ai un abonnement à vie à VPNSecure, permettant 5 connexions simultanées, des applications ou extensions pour navigateurs et smartphones, proposant des IP dans plus de 45 pays, et du "zero logging" (aucun enregistrement d'IP ou des données transitant par le VPN).

Maintenant, rentrons dans le vif du sujet ! Ce que nous allons mettre en place est un container openvpn client, qui établira un tunnel sécurisé en encrypté vers le fournisseur VPN et permettra de faire passer le trafic réseau d'autres containers de notre choix à travers celui-ci.
Comme l'article précédent traitait de l'installation et l'utilisation de Portainer, je vous montrerais les 2 méthodes pour cet article, pour lancer un container à la demande en CLI ou dans une stack (ou docker-compose) avec Portainer.

Préparation du NAS

Nous allons avoir besoin de créer un container VPN client, et allons utiliser l'image dperson/openvpn-client pour cela. Prenez l'habitude de lire en détails la fiche Docker Hub des images, c'est utile pour connaitre les prérequis, les options utilisables ou encore avoir des exemples de lancement de container ou docker-compose.

Commençons d'abord par télécharger l'image.

docker pull dperson/openvpn-client

Sur Synology, il faut au préalable exécuter un script pour créer la structure du tunnel VPN (/dev/net/tun) :

  • Utilisez le paquet "Editeur de texte" (installez-le depuis le "Centre de paquets" si ce n'est pas déjà fait) pour créer un nouveau fichier et collez-y le script suivant :
#!/bin/sh

# Create the necessary file structure for /dev/net/tun
if ( [ ! -c /dev/net/tun ] ); then
	if ( [ ! -d /dev/net ] ); then
		mkdir -m 755 /dev/net
	fi
	mknod /dev/net/tun c 10 200
fi

# Load the tun module if not already loaded
if ( !(lsmod | grep -q "^tun\s") ); then
	insmod /lib/modules/tun.ko
fi

# Load iptables mangle is not already loaded
if ( !(lsmod |grep -q "^iptable_mangle\s") ); then
	insmod /lib/modules/iptable_mangle.ko
fi
  • Sauvegardez le fichier à l'emplacement de votre choix (dans le futur dossier de configuration du container VPN pour ma part)
  • Nous allons ensuite créer une tâche planifiée pour lancer ce script à chaque démarrage du NAS. Ouvrez le "Panneau de contrôle" et sélectionnez "Planificateur de tâches".
  • Sélectionnez Créer, puis Tâche déclenchée et enfin Script défini par l'utilisateur.
  • Dans l'onglet "Général", nommez la tâche ("Tunnel VPN" par exemple). Sélectionnez l'utilisateur "root", l'événement "Démarrage" et cochez la case pour activer la tâche
  • Dans l'onglet "Paramètres de tâche", renseignez le chemin complet du script à exécuter précédé de la commande "bash".
  • Attention, pour que le script soit exécuté, il faut maintenant faire un redémarrage de votre NAS Synology.

Nous allons maintenant nous intéresser aux fichiers nécessaires pour établir la connexion à un serveur de votre fournisseur VPN.

  • Vous aurez besoin de télécharger les fichiers de configuration .ovpn depuis le site de ce dernier, ainsi que vos clés d'identification. Pour VPNSecure, j'obtiens autant de fichiers de configuration que de serveurs et pays.
  • Renommez le fichier de votre choix en "vpn.conf" et éditez-le à l'aide de "Editeur de texte" pour ajouter la ligne suivante pour éviter de saisir vos identifiants en clair : "auth-user-pass /vpn/vpn.auth" et "askpass /vpn/vpn.cert_auth"
  • Créez le fichier "vpn.auth" avec "Editeur de texte" et renseignez-y vos identifiants et mots de passe, chacun sur une ligne.
  • Si votre certificat a également un mot de passe, vous devrez ajouter la ligne "askpass /vpn/vpn.cert_auth" au fichier "vpn.conf", et l'y indiquer.

Vous aurez donc les fichiers suivants dans votre répertoire de configuration du container VPN client :

Exemple d'un fichier "vpn.conf" :

client
proto udp
dev tun
ca ca.crt
cert login.crt
key login.key
remote serveur-vpn port
cipher AES-256-CBC
verb 2
mute 20
keepalive 10 120
comp-lzo
persist-key
persist-tun
float
resolv-retry infinite
nobind
auth-nocache
remote-cert-tls server
auth-user-pass /vpn/vpn.auth
askpass /vpn/vpn.cert_auth

Exemple d'un fichier "vpn.auth" :

identifiant
mot-de-passe

Exemple d'un fichier "vpn.cert_auth" :

mot-de-passe-du-certificat

Passons maintenant aux choses sérieuses avec la création de notre container !

Création et utilisation du container VPN client en CLI

Pour créer notre container, rien de plus simple, connectez-vous en ssh au Synology et passez en root, puis saisissez la ligne suivante, en adaptant les chemins :

docker run -it --cap-add=NET_ADMIN --device /dev/net/tun --name vpn-client --dns 9.9.9.9 -v /volume1/docker/compose-vpn/test-vpn:/vpn -d dperson/openvpn-client:latest

Quelques explications sur les options utilisées :

  • "--cap-add=NET_ADMIN" permet d'interagir avec les équipements réseau du NAS
  • "--device /dev/net/tun" indique que nous allons utiliser l'équipement réseau créé pour le tunnel
  • "--name vpn_client" nous permet de spécifier le nom du container
  • "--dns 9.9.9.9" permet d'indiquer un serveur DNS en particulier, celui de Quad9 dans notre cas
  • "-v /volume1/docker/vpn:/vpn" spécifie le répertoire du Synology qui correspondra au répertoire "/vpn" interne au container
  • "-d dperson/openvpn-client:latest" définit l'image source utilisée pour la création de notre container

Après quelques secondes/minutes, le container devrait être démarré, ce que vous pouvez vérifier avec la commande suivante (en regardant le statut du container) :

# docker ps -a                                                                                     
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS                   PORTS                    NAMES
633e6a68dc37        dperson/openvpn-client:latest   "/sbin/tini -- /usr/…"   2 minutes ago       Up 2 minutes (healthy)                            vpn-client

Maintenant que notre container faisant office de client VPN est fonctionnel, nous allons créer et lancer un second container qui utilisera le tunnel VPN. Nous allons prendre comme exemple Transmission, à partir de l'image linuxserver/transmission. Nous pouvons voir dans la fiche descriptive de l'image que le port 9091 est celui utilisé pour l'interface web et que le port 51413 est celui utilisé pour le transit des données. Nous allons donc devoir reconstruire notre container vpn-client en spécifiant ces ports :

Il faut d'abord arrêter et supprimer notre container existant :

docker container stop vpn-client && docker container rm vpn-client

Puis lancer la commande :

docker run -it --cap-add=NET_ADMIN --device /dev/net/tun --name vpn-client --dns 9.9.9.9 -v /volume1/docker/compose-vpn/test-vpn:/vpn -p 9091:9091 -p 51413:51413 -d dperson/openvpn-client:latest

On vérifie que notre container est de nouveau lancé, et on peut cette fois apercevoir que les ports sont bien redirigés :

# docker ps -a
CONTAINER ID        IMAGE                           COMMAND                  CREATED              STATUS                        PORTS                                              NAMES
fb84062d4cc7        dperson/openvpn-client:latest   "/sbin/tini -- /usr/…"   About a minute ago   Up About a minute (healthy)   0.0.0.0:9091->9091/tcp, 0.0.0.0:51413->51413/tcp   vpn-client

Passons maintenant à Transmission, et téléchargeons l'image :

docker pull linuxserver/transmission

Et enfin nous allons créer notre container avec la commande suivante :

docker run -it --net=container:vpn-client --name=transmission-vpn -e PUID=1000 -e PGID=100 -v /volume1/docker/compose-vpn/test-vpn/transmission-config:/config -v /volume1/docker/compose-vpn/test-vpn/transmission-downloads:/downloads --restart unless-stopped -d linuxserver/transmission

La particularité de la commande ci-dessus est que nous utilisons l'option "--net=container:vpn-client" pour spécifier que le réseau doit passer par le container vpn-client.

Pour vérifier que le trafic réseau du container Transmission passe bien par le tunnel VPN, nous allons nous connecter à l'intérieur du container et interroger un serveur nous retournant notre adresse IP de connexion (qui devra être différente de celle de votre fournisseur d'accès internet) :

# docker exec -it transmission-vpn /bin/bash
root@transmission-vpn:/# curl ifconfig.me
ip.du.serveur.vpn

Création et utilisation du container VPN client dans une stack avec Portainer

Si vous n'avez pas lu l'article sur l'installation et l'utilisation de Portainer, je vous invite à le faire, histoire d'avoir les bases et de savoir ce qu'est une stack ou docker-compose.

Nous allons faire les mêmes déploiements qu'avec la première méthode, un container VPN client par lequel transitera tout le trafic réseau de la stack, et un container Transmission pour télécharger de manière anonyme.

Commençons par retranscrire nos commandes "docker run" en docker-compose. Pour rappel, les 2 commandes de lancement des containers sont les suivantes :

# docker run -it --cap-add=NET_ADMIN --device /dev/net/tun --name vpn-client --dns 9.9.9.9 -v /volume1/docker/compose-vpn/test-vpn:/vpn -p 9091:9091 -p 51413:51413 -d dperson/openvpn-client:latest
# docker run -it --net=container:vpn-client --name=transmission-vpn -e PUID=1000 -e PGID=100 -v /volume1/docker/compose-vpn/test-vpn/transmission-config:/config -v /volume1/docker/compose-vpn/test-vpn/transmission-downloads:/downloads --restart unless-stopped -d linuxserver/transmission

Et une fois transformées en docker-compose, cela donne :

version: "2"

services:
  vpn:
    image: dperson/openvpn-client:latest
    container_name: vpn
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun
    environment:
      - PUID=1000
      - PGID=100
    volumes:
         - /volume1/docker/compose-vpn/test-vpn:/vpn
    ports:
         - 9091:9091
         - 51413:51413
    dns:
      - 9.9.9.9
    restart: unless-stopped

  transmission:
    image: linuxserver/transmission:latest
    network_mode: service:vpn
    depends_on:
      - vpn
    container_name: vpn-transmission
    environment:
      - PUID=1000
      - PGID=100
    volumes:
      - /volume1/docker/compose-vpn/test-vpn/transmission-config:/config
      - /volume1/docker/compose-vpn/test-vpn/transmission-downloads:/downloads
    restart: unless-stopped

Tous les éléments que nous avions dans les commandes "docker run" sont présents. Deux nouvelles options sont visibles pour le service transmission :

  • "network_mode: service:vpn" qui permet d'indiquer que le container transmission devra utiliser le service s'appelant vpn.
  • "depends_on: - vpn" qui permet de ne pas démarrer le service transmission tant que le service s'appelant vpn n'est pas démarré.

Passons à la création de notre stack :

  • Dans Portainer, rendez-vous dans la gestion des stacks et créez-en une nouvelle avec le bouton "Add stack".
  • Donnez un nom à votre stack, "stackvpn" dans l'exemple.
  • Collez le contenu du docker-compose dans l'emplacement prévu.
  • Et cliquez sur "Deploy the stack".

De la même manière, vous pouvez vérifier que le trafic réseau du container vpn-transmission transite bien par le tunnel VPN. Pour cela, sur la ligne correspondant au container, cliquez sur l'icône ">_" (permettant de se connecter au shell du container) puis sur "Connect". Lancez ensuite la commande "curl ifconfig.me" pour vérifier que l'IP affichée est bien différente de celle de votre fournisseur d'accès à Internet.

Conclusion

Après avoir suivi cet article, vous êtes maintenant en mesure de sécuriser le trafic réseau de vos containers à travers un VPN, que ce soit pour anonymiser les flux ou bénéficier de services non disponibles chez vous.
Je ne peux que vous recommander de le mettre en application pour l'article sur l'automatisation du téléchargement de vos séries et films, en créant une stack comprenant tous les containers, pour sécuriser l'ensemble du trafic qui en sort.