Installer UFW sur un serveur ArchLinux
Dans ce bref billet, je vais vous expliquer comment je suis passé du firewall iptables
sur l'ArchLinux de mon serveur dédié OVH à ufw
.
Pourquoi ce changement ?
Mon serveur dédié OVH possède iptables
en pare-feu. Je ne m'en étais jamais trop occupé jusqu'à présent : mes services sont lancés avec Docker et j'expose leur ports. Et hop, tout fonctionne : la magie de l'informatique !
Je suis cependant un train de mettre en place un service Portainer pour contrôler à la fois les conteneurs lancés sur mon NAS à la maison (là où tourne Portainer) et sur mon serveur OVH dans le nuage. Pour ce faire, Portainer permet de déployer un service appelé portainer-agent
sur le serveur distant.
Pour sécuriser le tout, il est possible de faire de l'authentification mutuelle, mais je ne souhaite pas en arriver là. En effet, mon serveur OVH dans le cloud est relié par un tunnel OpenVPN avec mon NAS : ils sont donc visibles au sein d'un même réseau considéré comme local.
Je souhaite donc que mon conteneur portainer-agent
soit accessible uniquement depuis l'IP "réseau local VPN" du NAS et non par l'extérieur. Mais pour lancer le conteneur de cet agent, je dois exposer le port 9001, qui sera alors accessible à tout le monde, y compris du réseau public extérieur.
Problème : comment je restreins cet accès réseau ? Le moyen le plus simple est de le filtrer directement au niveau du firewall. Mais je suis une bille complète en iptables
.
Direction UFW (Uncomplicated FireWall)
ufw
est un firewall plus simple à utiliser que iptables
. Il permet d'aller dans le détail, certes, mais l'ajout de règle peut-être très simple pour les utilisateurs lambda comme moi.
Installer ufw
Vous pouvez normalement le trouver dans les repositories de votre distribution préférée. Pour Arch, une petite install via pacman
suffit largement.
# pacman -S ufw
Switch de iptables
à ufw
ufw
ne pourra pas réaliser la configuration si c'est iptables
qui est toujours au statut enabled
dans systemd.
Il faut alors désactiver iptables
, puis lancer et activer ufw
.
ufw
autorisant la connexion SSH avant de le lancer. Sinon, vous ne pourrez plus vous connecter à distance !# systemctl disable iptables
# ufw limit SSH
# systemctl start ufw
# systemctl enable ufw
# ufw enable
Attention de bien comprendre qu'on ne désinstalle pas iptables
. ufw
va permettre de le piloter plus simplement, mais comme disent certains :
iptables
, ce sont les fondations de ton firewall, le cordon bleu de ton tacos. - @Ormaz
Manipuler les règles et voir les règles en cours
Pour ajouter des règles, c'est assez simple avec ufw allow RULE
ou ufw deny RULE
. Le mot-clef limit
permet d'autoriser mais en limitant l'accès. C'est utile pour SSH par exemple, où le traffic sera interdit s'il y a plus de 6 connexions en moins de 30 secondes venant de la même IP.
Pour voir les règles, un petit coup de ufw status
et le tour est joué. Vous pouvez ajouter les paramètres verbose
et numbered
pour avoir le détail de l'action (entrant ou sortant pour le flux) et le numéro de la règle.
Régler mon problème d'accès
Je peux donc maintenant ajouter une règle qui me permet de n'autoriser qu'une connexion depuis une IP particulière sur le port exposé du conteneur de l'agent portainer.
# ufw allow proto tcp from 192.Z.Y.X to any port 9001
Et voilà ! Le problème est réglé !
Un petit aperçu des règles que j'ai sur mon serveur :
# ufw status verbose
Status: active
Logging: off
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp (SSH) LIMIT IN Anywhere
80 ALLOW IN Anywhere
443 ALLOW IN Anywhere
[...]
9001/tcp ALLOW IN 192.Z.Y.Z
[...]
WTF : pourquoi on peut toujours y accéder depuis n'importe où ?
Quand on regarde, le problème n'est pas réglé ! On peut quand même accéder au port 9001 du conteneur par le réseau public !
En fait, Docker écrit ses propres règles iptables
et elles sont appliquées en-dehors des vôtres !
Heureusement, nous ne sommes pas tout seul sur Internet à avoir le problème et il y a une solution assez élégante trouvable ici :
Il faut modifier le fichier /etc/ufw/after.rules
et y ajouter le bloc décrit dans le README du dépôt GitHub. Ce bloc permet de faire communiquer entre eux les réseaux internes de Docker mais d'empêcher le réseau public d'accéder aux ports exposés par les conteneurs.
Un petit redémarrage du service pour appliquer le tout avec un systemctl restart ufw
et hop, cette fois, c'est parfait !
Accéder à des conteneurs depuis le réseau public
Avec cette configuration, votre réseau docker - qui est un réseau privé - n'est pas accessible par un réseau public (le trafic Internet).
Pour rendre un service d'un conteneur Docker accessible depuis l'extérieur, il vous fait maintenant ajouter une route vers le port du conteneur. Par exemple, pour un conteneur Docker lancé avec le paramètre -p 6060:6767
, pour le rendre accessible depuis l'extérieur, vous devez réaliser les actions suivantes :
- ouvrir le port 6060 sur
ufw
pour que le port soit accessible depuis Internet
# ufw allow 6060/tcp
2. permettre le routage interne du flux vers le port 6767 du conteneur. Il vous faut l'IP du conteneur, accessible via docker inspect
.
# ufw route allow proto tcp from any to 172.X.Y.Z port 6767
3. redémarrer ufw
avec un petit ufw enable
.
Et hop, le tour est joué !
Je vous parlerai de Portainer une autre fois...