Comment verrouiller la sortie de Linux pour que rien ne fuie quand le VPN tombe
Le routage et le filtrage sont deux décisions distinctes. Verrouillez le hook de sortie, puis bornez les exceptions de point de terminaison, de DNS et d’administration dont le tunnel a besoin pour se reconnecter.
Imaginez un boîtier multimédia sur une liaison domestique qui ne doit atteindre internet que par un tunnel. Quand le tunnel tombe, l’application devrait se figer plutôt que continuer discrètement sur l’interface physique. Obtenir ce comportement est un problème de pare-feu et non de routage, et la distinction compte parce qu’une route peut être remplacée par un redémarrage du démon alors qu’un filtre reste là où vous l’avez placé. Voici comment le chemin du paquet décide réellement, puis comment borner les exceptions qui permettent au tunnel de se reconnecter.
La sortie locale est un hook différent du transfert
Un paquet qui quitte une application de la machine traverse le hook de sortie ; un paquet que la machine route pour un autre hôte traverse le transfert. Une politique qui ne mentionne que forward contraint le second et laisse le premier grand ouvert, et c’est pourquoi tant de verrouillages de sortie semblent corrects et ne font rien. La correspondance d’interface appartient à la même règle : oifname "tun0" accept laisse passer le trafic déjà routé par le tunnel. Routage et filtrage restent aussi des décisions distinctes, si bien qu’une route de liaison peut exister pendant que le filtre refuse le paquet. C’est sur cette séparation que vous comptez.
Une passerelle qui transfère pour d’autres appareils a besoin des deux hooks. Verrouiller seulement la sortie protège la machine elle-même et laisse chaque client en aval libre de fuir.
Écrivez la liste des exceptions du point de terminaison vers l’extérieur
Commencez par le point de terminaison du tunnel : une adresse de destination ou un petit ensemble approuvé, le protocole de transport et le port de destination, par exemple udp dport 1194 ip daddr 203.0.113.7 accept. Si le client résout un nom d’hôte, l’échange DNS d’amorçage a besoin de sa propre règle limitée au résolveur et au port 53, pas d’une autorisation globale vers l’adresse de ce résolveur. Chaque exception devrait nommer la raison pour laquelle elle existe. Une autorisation pour tout le trafic UDP vers le port du VPN couvre bien plus que le seul service authentifié que vous aviez en tête.
La résolution d’amorçage est l’endroit où les verrouillages pourrissent d’habitude. Un ensemble d’adresses rafraîchi par minuterie a besoin d’un comportement défini quand le rafraîchissement échoue, et ce comportement ne peut pas être d’ouvrir la liaison jusqu’à ce que cela réussisse. Rafraîchissez par le tunnel tant que le tunnel est monté, et revenez sinon au dernier point de terminaison sain connu.
L’administration locale mérite le même traitement. Un sous-réseau de gestion n’est pas digne de confiance parce que ses adresses sont privées, et une règle qui lui fait confiance invite un second chemin autour du verrouillage.
La correspondance d’interface ne prouve pas un tunnel sain
Les règles qui acceptent tout ce qui sort de tun0 supposent qu’un paquet sur cette interface vient du tunnel. Les noms d’interface sont recréés, et un nom n’est pas une identité cryptographique. Le pair peut aussi avoir disparu alors que l’interface reste montée, ce qui fait de la règle une inaction très convaincante.
Le suivi de connexions ajoute un piège apparenté. Une règle large pour les connexions établies rejoue l’autorisation qu’un flux a obtenue plus tôt, si bien qu’une session commencée avant la chute du tunnel continue ensuite. Restreignez l’acceptation avec état aux interfaces et adresses que vous visez réellement, sinon vous avez bâti un verrouillage qui s’ouvre tout seul. Les règles d’entrée et de sortie répondent aussi à des questions différentes, et durcir l’une en ignorant l’autre laisse la machine joignable dans la direction que vous n’avez pas envisagée.
Ce qui survit à un plantage du démon
Un filtre installé par un script qui s’exécute après la montée du tunnel disparaît avec le tunnel, précisément au moment où il était nécessaire. Chargez le verrouillage au démarrage et laissez le démon gérer seulement ses exceptions.
Supprimer la route par défaut n’est pas un substitut non plus. La route est un état que le démon possède et réécrit, et la retirer peut ôter le chemin nécessaire à la reconnexion. IPv6 a besoin de son propre plan, car la découverte de voisins et les annonces de routeur sont des services de lien qui doivent continuer de fonctionner pendant que le trafic ordinaire est bloqué. DHCP relève de la même catégorie. Notez ces éléments comme des exceptions ayant un but, au lieu de les découvrir plus tard sous forme de pannes.
Chemin de récupération avant déploiement
Testez le verrouillage de la façon dont il échouera : démarrer sans tunnel, tuer le démon, changer le point de terminaison et se reconnecter. Chaque cas devrait figer les applications et laisser le canal de récupération opérationnel. Faites-le depuis une console, car un shell distant est la session la plus susceptible d’être verrouillée par votre propre règle.
Vérifiez ensuite ce qu’une application ordinaire peut encore atteindre, avec une destination inoffensive et une requête que vous pouvez contrôler. Le résultat que vous voulez est un refus sur la liaison et un succès par le tunnel, pas un délai d’attente ambigu qui pourrait signifier l’un ou l’autre. Gardez le jeu de règles sous le même propriétaire que le reste du pare-feu au lieu de remplacer toute la table depuis un script shell. Une politique où chaque autorisation peut se justifier vaut plus qu’un long ensemble de règles que personne ne sait expliquer.