Comment transférer des ports via une passerelle Linux avec Iptables
Introduction
NAT, ou traduction d'adresse réseau, est un terme général désignant la manipulation de paquets afin de les rediriger vers une adresse alternative. Habituellement, cela est utilisé pour permettre au trafic de transcender les limites du réseau. Un hôte qui implémente NAT a généralement accès à deux réseaux ou plus et est configuré pour acheminer le trafic entre eux.
Le transfert de port est le processus de transfert des demandes d'un port spécifique vers un autre hôte, réseau ou port. Comme ce processus modifie la destination du paquet en cours de vol, il est considéré comme un type d'opération NAT.
Dans ce didacticiel, nous allons montrer comment utiliser iptables
pour transférer des ports vers des hôtes derrière un pare-feu à l'aide de techniques NAT. Ceci est utile si vous avez configuré un réseau privé, mais que vous souhaitez toujours autoriser un certain trafic à l'intérieur via une machine de passerelle désignée.
Conditions préalables
Pour suivre ce guide, vous aurez besoin de :
- Deux serveurs Ubuntu 20.04 configurés dans le même centre de données avec un réseau privé activé. Sur chacune de ces machines, vous devrez configurer un compte utilisateur non root avec des privilèges
sudo
. Vous pouvez apprendre comment faire cela avec notre guide sur Guide de configuration initiale du serveur Ubuntu 20.04. Assurez-vous d'ignorer l'Étape 4 de ce guide, car nous installerons et configurerons le pare-feu au cours de ce didacticiel. - Sur l'un de vos serveurs, configurez un modèle de pare-feu avec
iptables
afin qu'il puisse fonctionner comme votre serveur pare-feu. Vous pouvez le faire en suivant notre guide sur Comment implémenter un pare-feu de base avec Iptables sur Ubuntu 20.04. Une fois terminé, votre serveur pare-feu doit disposer des éléments suivants prêts à l'emploi :
Le serveur sur lequel vous configurez votre modèle de pare-feu servira de pare-feu et de routeur pour votre réseau privé. À des fins de démonstration, le deuxième hébergeur sera configuré avec un serveur Web accessible uniquement via son interface privée. Vous configurerez la machine pare-feu pour qu'elle transmette les requêtes reçues sur son interface publique au serveur Web, qu'elle atteindra sur son interface privée.
Détails de l'hôte
Avant de commencer, vous devez savoir quelles interfaces et adresses sont utilisées par vos deux serveurs.
Trouver les détails de votre réseau
Pour obtenir les détails de vos propres systèmes, commencez par trouver vos interfaces réseau. Vous pouvez trouver les interfaces sur vos machines et les adresses qui leur sont associées en exécutant ce qui suit :
ip -4 addr show scope global
Sample Output2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 203.0.113.1/18 brd 45.55.191.255 scope global eth0 valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 10.0.0.1/16 brd 10.132.255.255 scope global eth1 valid_lft forever preferred_lft forever
La sortie en surbrillance montre deux interfaces (eth0
et eth1
) et les adresses attribuées à chacune (203.0.113.1
et 10.0.0.1
respectivement). Pour savoir laquelle de ces interfaces est votre interface publique, exécutez cette commande :
ip route show | grep default
Outputdefault via 111.111.111.111 dev eth0
Les informations d'interface de cette sortie (eth0
dans cet exemple) seront l'interface connectée à votre passerelle par défaut. Il s'agit presque certainement de votre interface publique.
Trouvez ces valeurs sur chacune de vos machines et utilisez-les pour suivre le reste de ce guide.
Exemples de données utilisées dans ce guide
Pour clarifier les choses, nous utiliserons les affectations d'adresse et d'interface vides suivantes tout au long de ce didacticiel. Veuillez substituer vos propres valeurs à celles répertoriées ci-dessous :
Détails du réseau du serveur Web :
- Adresse IP publique :
203.0.113.1
- Adresse IP privée :
10.0.0.1
- Interface publique :
eth0
- Interface privée :
eth1
Détails du réseau de pare-feu :
- Adresse IP publique :
203.0.113.2
- Adresse IP privée :
10.0.0.2
- Interface publique :
eth0
- Interface privée :
eth1
Configuration du serveur Web
Commencez à vous connecter à votre hôte de serveur Web et en vous connectant avec votre utilisateur sudo
.
Installation de Nginx
La première étape consiste à installer Nginx sur l'hôte de votre serveur Web et à le verrouiller afin qu'il n'écoute que son interface privée. Cela garantira que votre serveur Web ne sera disponible que si vous avez correctement configuré la redirection de port.
Commencez par mettre à jour le cache de packages local :
sudo apt update
Ensuite, utilisez apt
pour télécharger et installer le logiciel :
sudo apt install nginx
Restreindre Nginx au réseau privé
Une fois Nginx installé, ouvrez le fichier de configuration du bloc de serveur par défaut pour vous assurer qu'il n'écoute que l'interface privée. Ouvrez le fichier à l'aide de votre éditeur de texte préféré. Ici, nous utiliserons nano
:
sudo nano /etc/nginx/sites-enabled/default
À l'intérieur, trouvez la directive listen
. Il doit être répertorié deux fois de suite vers le haut de la configuration :
/etc/nginx/sites-enabled/default
server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; . . . }
À la première directive listen
, ajoutez l'adresse IP privée de votre serveur Web et deux-points avant 80
pour indiquer à Nginx de n'écouter que sur l'interface privée. Nous démontrons uniquement le transfert IPv4 dans ce guide, vous pouvez donc supprimer la deuxième directive d'écoute, qui est configurée pour IPv6.
Modifiez ensuite les directives listen
comme suit :
/etc/nginx/sites-enabled/default
server { listen 10.0.0.1:80 default_server; . . . }
Enregistrez et fermez le fichier lorsque vous avez terminé. Si vous avez utilisé nano
, vous pouvez le faire en appuyant sur CTRL + X
, puis Y
et ENTER
.
Testez maintenant le fichier pour les erreurs de syntaxe :
sudo nginx -t
Outputnginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
S'il n'y a pas d'erreurs dans la sortie, redémarrez Nginx pour activer la nouvelle configuration :
sudo systemctl restart nginx
Vérification de la restriction réseau
À ce stade, il est utile de vérifier le niveau d'accès dont vous disposez à votre serveur Web.
Depuis votre serveur firewall, essayez d'accéder à votre serveur web depuis l'interface privée avec la commande suivante :
curl --connect-timeout 5 10.0.0.1
En cas de succès, votre sortie entraînera le message suivant :
Output<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . .
Si vous essayez d'utiliser l'interface publique, vous recevrez un message indiquant qu'il ne peut pas se connecter :
curl --connect-timeout 5 203.0.113.1
Outputcurl: (7) Failed to connect to 203.0.113.1 port 80: Connection refused
Ces résultats sont attendus.
Configuration du pare-feu pour transférer le port 80
Vous allez maintenant travailler sur la mise en œuvre de la redirection de port sur votre machine pare-feu .
Activer le transfert dans le noyau
La première chose que vous devez faire est d'activer le transfert de trafic au niveau du noyau. Par défaut, la plupart des systèmes ont le transfert désactivé.
Pour activer le transfert de port pour cette session uniquement, exécutez la commande suivante :
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
Output1
Pour activer la redirection de port de manière permanente, vous devrez modifier le fichier /etc/sysctl.conf
. Vous pouvez le faire en ouvrant le fichier avec les privilèges sudo
:
sudo nano /etc/sysctl.conf
Dans le fichier, recherchez et décommentez la ligne qui se lit comme suit :
/etc/sysctl.conf
net.ipv4.ip_forward=1
Enregistrez et fermez le fichier lorsque vous avez terminé.
Appliquez ensuite les paramètres de ce fichier. Exécutez d'abord la commande suivante :
sudo sysctl -p
Outputnet.ipv4.ip_forward = 1
Exécutez ensuite la même commande, mais remplacez le drapeau -p
par --system
:
sudo sysctl --system
Output. . . * Applying /usr/lib/sysctl.d/50-pid-max.conf ... kernel.pid_max = 4194304 * Applying /etc/sysctl.d/99-cloudimg-ipv6.conf ... net.ipv6.conf.all.use_tempaddr = 0 net.ipv6.conf.default.use_tempaddr = 0 * Applying /etc/sysctl.d/99-sysctl.conf ... net.ipv4.ip_forward = 1 * Applying /usr/lib/sysctl.d/protect-links.conf ... fs.protected_fifos = 1 fs.protected_hardlinks = 1 fs.protected_regular = 2 fs.protected_symlinks = 1 * Applying /etc/sysctl.conf ... net.ipv4.ip_forward = 1
Ajout de règles de transfert au pare-feu de base
Ensuite, vous configurerez votre pare-feu afin que le trafic entrant dans votre interface publique (eth0
) sur le port 80
soit redirigé vers votre interface privée (eth1
).
Le pare-feu que vous avez configuré dans le tutoriel prérequis a votre chaîne FORWARD
définie sur le trafic DROP
par défaut. Vous devez ajouter des règles qui vous permettront de transférer les connexions vers votre serveur Web. Pour des raisons de sécurité, vous allez le verrouiller assez étroitement afin que seules les connexions que vous souhaitez transférer soient autorisées.
Dans la chaîne FORWARD
, vous accepterez les nouvelles connexions destinées au port 80
provenant de votre interface publique et se rendant à votre interface privée. Les nouvelles connexions sont identifiées par l'extension conntrack
et seront spécifiquement représentées par un paquet TCP SYN comme dans ce qui suit :
sudo iptables -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
Cela laissera le premier paquet, destiné à établir une connexion, à travers le pare-feu. Vous devrez également autoriser tout trafic ultérieur dans les deux sens résultant de cette connexion. Pour autoriser le trafic ESTABLISHED
et RELATED
entre vos interfaces publiques et privées, exécutez les commandes suivantes. D'abord pour votre interface publique :
sudo iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
Ensuite pour votre interface privée :
sudo iptables -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
Vérifiez que votre stratégie sur la chaîne FORWARD
est définie sur DROP
:
sudo iptables -P FORWARD DROP
À ce stade, vous avez autorisé un certain trafic entre vos interfaces publiques et privées à traverser votre pare-feu. Cependant, vous n'avez pas configuré les règles qui indiqueront réellement à iptables
comment traduire et diriger le trafic.
Ajout correct des règles NAT aux paquets directs
Ensuite, vous ajouterez les règles qui indiqueront à iptables
comment acheminer votre trafic. Vous devez effectuer deux opérations distinctes pour que iptables
modifie correctement les paquets afin que les clients puissent communiquer avec le serveur Web.
La première opération, appelée DNAT
, aura lieu dans la chaîne PREROUTING
de la table nat
. DNAT
est une opération qui modifie l'adresse de destination d'un paquet afin de lui permettre d'être acheminé correctement lors de son passage entre les réseaux. Les clients du réseau public se connecteront à votre serveur pare-feu et n'auront aucune connaissance de la topologie de votre réseau privé. Par conséquent, vous devez modifier l'adresse de destination de chaque paquet afin que lorsqu'il est envoyé sur votre réseau privé, il sache comment atteindre correctement votre serveur Web.
Étant donné que vous ne configurez que la redirection de port et que vous n'effectuez pas de NAT sur chaque paquet qui atteint votre pare-feu, vous devrez faire correspondre le port 80
sur votre règle. Vous associerez les paquets destinés au port 80
à l'adresse IP privée de votre serveur Web (10.0.0.1
dans l'exemple suivant) :
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1
Ce processus prend soin de la moitié de l'image. Le paquet doit être acheminé correctement vers votre serveur Web. Cependant, à l'heure actuelle, le paquet aura toujours l'adresse d'origine du client comme adresse source. Le serveur tentera d'envoyer la réponse directement à cette adresse, ce qui rendra impossible l'établissement d'une connexion TCP légitime.
Sur DigitalOcean, les paquets quittant un Droplet avec une adresse source différente seront en fait supprimés par l'hyperviseur, de sorte que vos paquets à ce stade n'atteindront même jamais le serveur Web (ce qui sera corrigé en implémentant SNAT momentanément). Il s'agit d'une mesure anti-usurpation d'identité mise en place pour prévenir les attaques où de grandes quantités de données doivent être envoyées à l'ordinateur d'une victime en falsifiant l'adresse source dans la demande. Pour en savoir plus, lisez cette réponse dans notre communauté.
Pour configurer un routage approprié, vous devez également modifier l'adresse source du paquet lorsqu'il quitte le pare-feu en route vers le serveur Web. Vous devez remplacer l'adresse source par l'adresse IP privée de votre serveur pare-feu (10.0.0.2
dans l'exemple suivant). La réponse sera ensuite renvoyée au pare-feu, qui pourra alors la renvoyer au client comme prévu.
Pour activer cette fonctionnalité, ajoutez une règle à la chaîne POSTROUTING
de la table nat
, qui est évaluée juste avant que les paquets ne soient envoyés sur le réseau. Vous ferez correspondre les paquets destinés à votre serveur Web par adresse IP et port :
sudo iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 -d 10.0.0.1 -j SNAT --to-source 10.0.0.2
Une fois cette règle en place, votre serveur Web devrait être accessible en pointant votre navigateur Web sur l'adresse publique de votre machine pare-feu :
curl 203.0.113.2
Output<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . .
Votre configuration de redirection de port est maintenant terminée.
Ajustement de l'ensemble de règles permanentes
Maintenant que vous avez configuré la redirection de port, vous pouvez l'enregistrer dans votre ensemble de règles permanentes.
Si vous ne vous souciez pas de perdre les commentaires qui se trouvent dans votre jeu de règles actuel, utilisez la commande netfilter-persistent
pour utiliser le service iptables
et enregistrez vos règles :
sudo service netfilter-persistent save
Output * Saving netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save [ OK ]
Si vous souhaitez conserver les commentaires dans votre fichier, ouvrez-le et modifiez-le manuellement :
sudo nano /etc/iptables/rules.v4
Vous devrez ajuster la configuration dans le tableau filter
pour les règles de chaîne FORWARD
qui ont été ajoutées. Vous devrez également ajuster la section qui configure la table nat
afin que vous puissiez ajouter vos règles PREROUTING
et POSTROUTING
. Le contenu ressemblera à ce qui suit :
/etc/iptables/rules.v4
*filter # Allow all outgoing, but drop incoming and forwarding packets by default :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # Custom per-protocol chains :UDP - [0:0] :TCP - [0:0] :ICMP - [0:0] # Acceptable UDP traffic # Acceptable TCP traffic -A TCP -p tcp --dport 22 -j ACCEPT # Acceptable ICMP traffic # Boilerplate acceptance policy -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A INPUT -i lo -j ACCEPT # Drop invalid packets -A INPUT -m conntrack --ctstate INVALID -j DROP # Pass traffic to protocol-specific chains ## Only allow new connections (established and related should already be handled) ## For TCP, additionally only allow new SYN packets since that is the only valid ## method for establishing a new TCP connection -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP # Reject anything that's fallen through to this point ## Try to be protocol-specific w/ rejection message -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable # Rules to forward port 80 to our web server # Web server network details: # * Public IP Address: 203.0.113.1 # * Private IP Address: 10.0.0.1 # * Public Interface: eth0 # * Private Interface: eth1 # # Firewall network details: # # * Public IP Address: 203.0.113.2 # * Private IP Address: 10.0.0.2 # * Public Interface: eth0 # * Private Interface: eth1 -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # End of Forward filtering rules # Commit the changes COMMIT *raw :PREROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] # Rules to translate requests for port 80 of the public interface # so that we can forward correctly to the web server using the # private interface. # Web server network details: # * Public IP Address: 203.0.113.1 # * Private IP Address: 10.0.0.1 # * Public Interface: eth0 # * Private Interface: eth1 # # Firewall network details: # # * Public IP Address: 203.0.113.2 # * Private IP Address: 10.0.0.2 # * Public Interface: eth0 # * Private Interface: eth1 -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1 -A POSTROUTING -d 10.0.0.1 -o eth1 -p tcp --dport 80 -j SNAT --to-source 10.0.0.2 # End of NAT translations for web server traffic COMMIT *security :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT
Enregistrez et fermez le fichier une fois que vous avez ajouté le contenu et ajusté les valeurs pour refléter votre propre environnement réseau.
Ensuite, testez la syntaxe de votre fichier de règles :
sudo sh -c "iptables-restore -t < /etc/iptables/rules.v4"
Si aucune erreur n'est détectée, chargez l'ensemble de règles :
sudo service netfilter-persistent reload
Output * Loading netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables start run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables start [ OK ]
Vérifiez maintenant que votre serveur Web est toujours accessible via l'adresse IP publique de votre pare-feu :
curl 203.0.113.2
Cela devrait fonctionner comme avant.
Conclusion
À présent, vous devriez être à l'aise avec le transfert de ports sur un serveur Linux avec iptables
. Le processus implique d'autoriser le transfert au niveau du noyau, de configurer l'accès pour permettre le transfert du trafic du port spécifique entre deux interfaces sur le système de pare-feu et de configurer les règles NAT afin que les paquets puissent être correctement acheminés. Cela peut sembler un processus lourd, mais cela démontre également la flexibilité du cadre de filtrage de paquets netfilter
et du pare-feu iptables
. Cela peut être utilisé pour dissimuler la topologie de votre réseau privé tout en permettant au trafic de service de circuler librement à travers votre pare-feu de passerelle.