Comment configurer un pare-feu Iptables pour protéger le trafic entre vos serveurs

De Get Docs
Aller à :navigation, rechercher

Introduction

Le déploiement de composants discrets dans la configuration de votre application sur différents nœuds est un moyen courant de réduire la charge et de commencer à évoluer horizontalement. Un exemple typique est la configuration d'une base de données sur un serveur distinct de votre application. Bien qu'il existe un grand nombre d'avantages avec cette configuration, la connexion via un réseau implique un nouvel ensemble de problèmes de sécurité.

Dans ce guide, nous allons vous montrer comment configurer un pare-feu simple sur chacun de vos serveurs dans une configuration distribuée. Nous configurerons notre politique pour autoriser le trafic légitime entre nos composants tout en refusant tout autre trafic.

Pour la démonstration de ce guide, nous utiliserons deux serveurs Ubuntu 14.04. L'un aura une instance WordPress servie avec Nginx et l'autre hébergera la base de données MySQL pour l'application. Bien que nous utiliserons cette configuration comme exemple, vous devriez être en mesure d'extrapoler les techniques impliquées pour répondre aux exigences de votre propre serveur.

Conditions préalables

Pour commencer, vous devrez disposer de deux nouveaux serveurs Ubuntu 14.04. Ajoutez un compte d'utilisateur régulier avec des privilèges sudo sur chacun. Pour savoir comment procéder correctement, suivez notre Guide de configuration initiale du serveur Ubuntu 14.04.

La configuration de l'application que nous allons sécuriser est basée sur ce guide. Si vous souhaitez suivre, configurez vos serveurs d'application et de base de données comme indiqué dans ce didacticiel.

Configuration d'un pare-feu de base

Nous commencerons par implémenter une configuration de pare-feu de base pour chacun de nos serveurs. La politique que nous allons mettre en œuvre adopte une approche axée sur la sécurité. Nous allons verrouiller presque tout sauf le trafic SSH, puis percer des trous dans le pare-feu pour notre application spécifique.

Le pare-feu de ce guide fournit la configuration de base dont nous avons besoin. Installez le package iptables-persistent et collez les règles de base dans le fichier /etc/iptables/rules.v4 :

sudo apt-get update
sudo apt-get install iptables-persistent
sudo nano /etc/iptables/rules.v4

/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

# 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]
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

Si vous l'implémentez dans un environnement en direct , ne rechargez pas encore vos règles de pare-feu . Le chargement de l'ensemble de règles de base décrit ici interrompra immédiatement la connexion entre votre application et le serveur de base de données. Nous devrons ajuster les règles pour refléter nos besoins opérationnels avant de recharger.

Découvrez les ports utilisés par vos services

Afin d'ajouter des exceptions pour permettre la communication entre nos composants, nous devons connaître les ports réseau utilisés. Nous pourrions trouver les ports réseau corrects en examinant nos fichiers de configuration, mais une méthode indépendante de l'application pour trouver les ports corrects consiste simplement à vérifier quels services écoutent les connexions sur chacune de nos machines.

Nous pouvons utiliser l'outil netstat pour le savoir. Étant donné que notre application ne communique que sur IPv4, nous ajouterons l'argument -4 mais vous pouvez le supprimer si vous utilisez également IPv6. Les autres arguments dont nous avons besoin pour trouver nos services en cours d'exécution sont -plunt.

Sur votre serveur Web, nous verrions quelque chose comme ceci :

sudo netstat -4plunt
OutputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1058/sshd
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      4187/nginx

La première colonne en surbrillance indique l'adresse IP et le port sur lesquels le service en surbrillance vers la fin de la ligne écoute. L'adresse spéciale 0.0.0.0 signifie que le service en question est à l'écoute sur toutes les adresses disponibles.

Sur notre serveur de base de données, nous verrions quelque chose comme ceci :

sudo netstat -4plunt
OutputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1097/sshd
tcp        0      0 192.0.2.30:3306     0.0.0.0:*               LISTEN      3112/mysqld

Vous pouvez lire ces colonnes exactement de la même manière. Dans l'exemple ci-dessus, l'adresse 192.0.2.30 représente l'adresse IP privée du serveur de base de données. Dans la configuration de l'application, nous avons verrouillé MySQL sur l'interface privée pour des raisons de sécurité.

Prenez note des valeurs que vous trouvez dans cette étape. Ce sont les détails de mise en réseau dont nous avons besoin pour ajuster la configuration de notre pare-feu.

Dans notre scénario d'exemple, nous pouvons noter que sur notre serveur Web, nous devons nous assurer que les ports suivants sont accessibles :

  • Port 80 sur toutes les adresses
  • Port 22 sur toutes les adresses (déjà pris en compte dans les règles de pare-feu)

Notre serveur de base de données devrait s'assurer que les ports suivants sont accessibles :

  • Port 3306 sur l'adresse 192.0.2.30 (ou l'interface qui lui est associée)
  • Port 22 sur toutes les adresses (déjà pris en compte dans les règles de pare-feu)

Ajuster les règles du pare-feu du serveur Web

Maintenant que nous avons les informations de port dont nous avons besoin, nous allons ajuster l'ensemble de règles de pare-feu de notre serveur Web. Ouvrez le fichier de règles dans votre éditeur avec les privilèges sudo :

sudo nano /etc/iptables/rules.v4

Sur le serveur Web, nous devons ajouter le port 80 à notre liste de trafic acceptable. Puisque le serveur écoute sur toutes les adresses disponibles, nous ne restreindrons pas la règle par interface ou adresse de destination.

Nos visiteurs Web utiliseront le protocole TCP pour se connecter. Notre framework de base a déjà une chaîne personnalisée appelée TCP pour les exceptions d'application TCP. Nous pouvons ajouter le port 80 à cette chaîne, juste en dessous de l'exception pour notre port SSH :

/etc/iptables/rules.v4

*filter
. . .

# Acceptable TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 80 -j ACCEPT

. . .

Notre serveur Web initiera la connexion avec notre serveur de base de données. Notre trafic sortant n'est pas limité dans notre pare-feu et le trafic entrant associé aux connexions établies est autorisé, nous n'avons donc pas à ouvrir de ports supplémentaires sur ce serveur pour autoriser cette connexion.

Enregistrez et fermez le fichier lorsque vous avez terminé. Notre serveur Web a maintenant une politique de pare-feu qui autorisera tout le trafic légitime tout en bloquant tout le reste.

Testez votre fichier de règles pour les erreurs de syntaxe :

sudo iptables-restore -t < /etc/iptables/rules.v4

Si aucune erreur de syntaxe ne s'affiche, rechargez le pare-feu pour implémenter le nouveau jeu de règles :

sudo service iptables-persistent reload

Ajuster les règles de pare-feu du serveur de base de données

Sur notre serveur de base de données, nous devons autoriser l'accès au port 3306 sur l'adresse IP privée de notre serveur. Dans notre cas, cette adresse était 192.0.2.30. Nous pouvons limiter spécifiquement l'accès destiné à cette adresse, ou nous pouvons limiter l'accès en faisant correspondre l'interface à laquelle cette adresse est attribuée.

Pour trouver l'interface réseau associée à cette adresse, tapez :

ip -4 addr show scope global
Output2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 203.0.113.5/24 brd 104.236.113.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 192.0.2.30/24 brd 192.0.2.255 scope global eth1
       valid_lft forever preferred_lft forever

Les zones en surbrillance indiquent que l'interface eth1 est associée à cette adresse.

Ensuite, nous allons ajuster les règles de pare-feu sur le serveur de base de données. Ouvrez le fichier de règles avec les privilèges sudo sur votre serveur de base de données :

sudo nano /etc/iptables/rules.v4

Encore une fois, nous ajouterons une règle à notre chaîne TCP pour former une exception pour la connexion entre nos serveurs Web et de base de données.

Si vous souhaitez restreindre l'accès en fonction de l'adresse réelle en question, vous ajouterez la règle suivante :

/etc/iptables/rules.v4

*filter
. . .

# Acceptable TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 3306 -d 192.0.2.30 -j ACCEPT

. . .

Si vous préférez autoriser l'exception en fonction de l'interface qui héberge cette adresse, vous pouvez ajouter une règle similaire à celle-ci :

/etc/iptables/rules.v4

*filter
. . .

# Acceptable TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 3306 -i eth1 -j ACCEPT

. . .

Enregistrez et fermez le fichier lorsque vous avez terminé.

Vérifiez les erreurs de syntaxe avec cette commande :

sudo iptables-restore -t < /etc/iptables/rules.v4

Lorsque vous êtes prêt, rechargez les règles de pare-feu :

sudo service iptables-persistent reload

Vos deux serveurs devraient maintenant être protégés sans restreindre le flux de données nécessaire entre eux.

Conclusion

L'implémentation d'un pare-feu approprié doit toujours faire partie de votre plan de déploiement lors de la configuration d'une application. Bien que nous ayons démontré cette configuration en utilisant les deux serveurs exécutant Nginx et MySQL pour fournir une instance WordPress, les techniques présentées ci-dessus sont applicables quels que soient vos choix technologiques spécifiques.

Pour en savoir plus sur les pare-feu et iptables en particulier, consultez les guides suivants :