[OpenBSD]

[Précédent : Authpf: Shell Utilisateur pour les Passerelles d'Authentification] [Index]

PF : Exemple #1 : Pare-feu SoHo


Table des Matières


Le Scenario

Dans cet exemple, PF fonctionne sur une machine OpenBSD jouant le rôle de pare-feu et de passerelle NAT pour un réseau SoHo. L'objectif global est de fournir un accès Internet au réseau local et de fournir un accès limité au pare-feu depuis Internet. Ce document a pour but de vous montrer comment on construit un jeu de règles correspondant à l'objectif précité.

Le Réseau

Le réseau est conçu de la manière suivante :
    
  [ COMP1 ]    [ COMP3 ]
      |            |                               ADSL
   ---+------+-----+------- fxp0 [ OpenBSD ] ep0 -------- ( Internet )
             |
         [ COMP2 ]

Il y a un certain nombre de machines sur le réseau interne. Le diagramme en montre trois mais le vrai nombre n'est pas une donnée utile. Ces machines sont des stations de travail normales servant à surfer sur le web, écrire des messages électroniques, participer à des forums de discussion en ligne, etc. Le réseau interne utilise le bloc de réseau 192.168.0.0 / 255.255.255.0.

Le routeur OpenBSD est une machine dotée d'un Pentium 100 et de deux cartes réseau : une 3Com 3c509B (ep0) et d'une Intel EtherExpress Pro/100 (fxp0). Le routeur a une connexion ADSL vers Internet et utilise la NAT pour partager cette connexion avec le réseau interne. L'adresse IP de l'interface externe est attribuée dynamiquement par le Fournisseur d'Accès Internet.

Les Objectifs

Les objectifs sont les suivants :

Préparation

Ce document suppose que le hôte OpenBSD a été correctement configuré pour fonctionner comme routeur : configuration réseau, connexion Internet, net.inet.ip.forwarding avec une valeur de "1" etc.

Le Jeu de Règles

Les sections ci-après détaillent la manière dont le jeu de règles répondra aux objectifs précités.

Macros

Les macros suivantes sont définies pour rendre la maintenance et la lecture du jeu de règles plus faciles :
int_if = "fxp0"
ext_if = "ep0"

tcp_services = "{ 22, 113 }"
icmp_types = "echoreq"

priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }"

Les deux premières lignes définissent les interfaces réseau sur lesquelles le filtrage sera effectué. Les deux lignes suivantes listent les numéros de port TCP des services ouverts depuis Internet (SSH et ident/auth) et les types de paquets ICMP qui sont autorisés à parvenir jusqu'aù pare-feu. La dernière ligne définit le réseau de loopback et les blocs d'adresses RFC 1918.

Remarque : Si la connexion Internet ADSL nécessite l'utilisation de PPPoE, le filtrage et la NAT s'effectueront sur l'interface tun0 au lieu de ep0.

Options

Les deux options suivantes spécifient la réponse par défaut fournie par les règles de filtrage block et activent la collecte de statistiques sur l'interface externe :
set block-policy return
set loginterface $ext_if

Scrub

Il n'y a aucune raison pour ne pas utiliser la normalisation de paquets recommandée pour tous les paquets entrants. Il suffit d'utiliser la ligne suivante :
scrub in all

Traduction d'Adresses Réseau

Pour effectuer la NAT du réseau interne, la règle de nat suivante est utilisée :
nat on $ext_if from $int_if:network to any -> ($ext_if)

Vu que l'adresse IP de l'interface externe est attribuée dynamiquement, des parenthèses sont utilisés autour de l'interface de traduction afin que PF tienne compte automatiquement des changements d'adresse IP sur cette interface.

Redirection

La seule redirection nécessaire est pour ftp-proxy(8) afin de permettre aux clients FTP sur le réseau interne de se connecter à des serveurs FTP sur Internet.
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021

Il est à noter que cette règle ne fonctionnera que pour les connexions FTP au port 21. Si les utilisateurs se connectent de manière régulière à des serveurs FTP sur d'autres ports, une liste devra être utilisée pour spécifier le port de destination, par exemple : from any to any port { 21, 2121 }.

Règles de Filtrage

Détaillons maintenant les règles de filtrage. Commencez par l'interdiction par défaut de tout trafic :
block all

Avec cette règle, aucun trafic ne sera autorisé y compris le trafic provenant du réseau interne. Les règles ci-après vont ouvrir un certain nombre de flux sur le pare-feu afin de répondre aux objectifs précités et d'ouvrir toutes les interfaces virtuelles nécessaires.

Tout système Unix a une interface de "loopback". C'est une interface virtuelle représentant un réseau utilisé par les applications pour établir des canaux de communication locaux à la machine. De manière générale, tout le trafic au niveau de l'interface de "loopback" doit être autorisé. Sous OpenBSD, l'interface de "loopback" est lo(4).

pass quick on lo0 all

Ensuite, les adresses RFC 1918 doivent être bloquées en entrée et en sortie de l'interface externe. Ces adresses ne doivent jamais apparaître sur le réseau Internet public. Leur filtrage permet de s'assurer que le routeur ne divulgue pas les adresses utilisées par le réseau interne et de bloquer tous les paquets entrants avec une adresse source appartenant à l'un de ces réseaux.

block drop in  quick on $ext_if from $priv_nets to any
block drop out quick on $ext_if from any to $priv_nets

Il est à noter que block drop est utilisé pour dire à PF de ne pas répondre par un paquet TCP RST ou ICMP "Unreachable". Vu que les adresses correspondant à la RFC 1918 n'existent pas sur Internet, tout paquet envoyé vers une de ces adresses ne sera jamais acheminé vers sa destination de toute façon. L'option quick est utilisée pour dire à PF de ne pas évaluer le reste des règles de filtrage si un paquet correspond à l'une des règles ci-dessus; les paquets de et vers les réseaux $priv_nets seront immédiatement détruits.

Maintenant, il faut ouvrir les ports utilisés par les services réseau disponibles depuis Internet :

pass in on $ext_if inet proto tcp from any to ($ext_if) \
   port $tcp_services flags S/SA keep state

La spécification des ports réseau par le biais de la macro $tcp_services rend l'ouverture de nouveaux services pour des connexions provenant d'Internet plus facile dans la mesure où il suffira de modifier la macro et recharger le jeu de règles. Des services UDP peuvent aussi être mis à disposition en créant la macro $udp_services et en ajoutant une règle de filtrage adéquate similaire à la règle de filtrage ci-dessus en spécifiant proto udp.

Le trafic ICMP doit aussi être permis :

pass in inet proto icmp all icmp-type $icmp_types keep state

Comme pour la macro $tcp_services, la macro $icmp_types peut facilement être modifiée pour changer les types des paquets ICMP qui doivent être autorisés à atteindre le pare-feu. Notez que cette règle s'applique à toutes les interfaces réseau.

Maintenant, le trafic en provenance du réseau interne doit être autorisé. Nous supposerons que les utilisateurs du réseau interne savent ce qu'ils font et ne provoqueront pas de problème sur Internet. Ce n'est pas nécessairement une bonne supposition; pour certains environnements, il serait plus judicieux d'utiliser un jeu de règles plus restrictif.

pass in on $int_if from $int_if:network to any keep state

La règle ci-dessus permettra à n'importe quelle machine interne d'envoyer des paquets à travers le pare-feu; cependant, le pare-feu ne sera pas autorisé à à initier une connexion vers une machine interne. Est-ce une bonne idée ? Ceci dépendra de certains détails fins de la configuration réseau. Si le pare-feu est aussi un serveur DHCP, il aurait éventuellement besoin de vérifier la présence d'une adresse ("ping") pour voir si elle est disponible avant de l'attribuer à une machine. Permettre au pare-feu de se connecter au réseau interne veut dire aussi que quelqu'un qui accéderait en SSH au pare-feu depuis Internet sera autorisé à accèder aux machines sur le réseau. Gardez à l'esprit qu'interdire au pare-feu de communiquer directement avec le réseau n'est pas d'un grand bénéfice du point de vue de la sécurité; si quelqu'un accède au pare-feu, il pourra très probablement altérer les règles de filtrage de toute façon. En ajoutant la règle suivante, le pare-feu sera capable d'initier des connexions vers le réseau interne :

pass out on $int_if from any to $int_if:network keep state

Notez que si les deux lignes ci-dessus sont utilisées, l'option keep state n'est pas nécessaire car il y a une règle pour laisser passer les paquets dans les deux directions. Cependant, si la ligne pass out n'est pas utilisée, la règle pass in doit comporter l'option keep state. Garder l'état d'une connexion permet aussi d'améliorer les performances : Les tables d'état sont vérifiées avant l'évaluation des règles, et si un état est trouvé, le passage du paquet à travers le pare-feu est autorisé sans que le jeu de règles ne soit évalué. Cette méthode de fonctionnement peut offrir de meilleures performances pour un pare-feu très chargé bien que pour un système aussi simple, la charge ne sera très certainement pas assez significative pour que cela fasse une différence.

Finalement, il faut laisser le trafic sortir de l'interface externe :

pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state

Le trafic TCP, UDP, et ICMP à destination d'Internet est autorisé sortir du pare-feu. L'information sur l'état des connexions est sauvegardée pour permettre aux paquets de retour de passer à leur tour la barrière que constitue le pare-feu.

Le Jeu de Règles Complet

# macros
int_if = "fxp0"
ext_if = "ep0"

tcp_services = "{ 22, 113 }"
icmp_types = "echoreq"

priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }"
          
# options
set block-policy return
set loginterface $ext_if

# scrub
scrub in all

# nat/rdr
nat on $ext_if from $int_if:network to any -> ($ext_if)
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 \
   port 8021

# règles de filtrage
block all

pass quick on lo0 all

block drop in  quick on $ext_if from $priv_nets to any
block drop out quick on $ext_if from any to $priv_nets

pass in on $ext_if inet proto tcp from any to ($ext_if) \
   port $tcp_services flags S/SA keep state

pass in inet proto icmp all icmp-type $icmp_types keep state

pass in  on $int_if from $int_if:network to any keep state
pass out on $int_if from any to $int_if:network keep state

pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state

[Précédent : Authpf: Shell Utilisateur pour les Passerelles d'Authentification] [Index]


[back] www@openbsd.org
Originally [OpenBSD: example1.html,v 1.12 ]
$Translation: example1.html,v 1.2 2004/01/02 21:49:07 saad Exp $
$OpenBSD: example1.html,v 1.2 2004/01/03 19:45:23 jufi Exp $