[OpenBSD]

[Zurück: Firewal-Redundanz mit CARP und pfsync] [Inhalt]

PF: Beispiel: Firewall für zuhause oder ein kleines Büro


Inhaltsverzeichnis


Das Szenario

In diesem Beispiel läuft PF auf einer OpenBSD-Maschine, derren Aufgabe es ist, als Firewall und NAT-Gateway für ein kleines Netzwerk zuhause oder in einem Büro zu agieren. Das gesamte Ziel ist, dem Netzwerk Internetzugriff und begrenzten Zugriff zur Firewall-Maschine vom Internet aus zu gewähren. Dieses Dokument wird einen kompletten Regelsatz durchgehen, der genau das macht.

Das Netzwerk

Das Netzwerk ist wie folgt aufgebaut:
    
  [ COMP1 ]    [ COMP3 ]
      |            |                               ADSL
   ---+------+-----+------- fxp0 [ OpenBSD ] ep0 -------- ( Internet )
             |
         [ COMP2 ]

In diesem internen Netzwerk befinden sich einige Computer; das Diagramm zeigt drei, aber die tatsächliche Anzahl ist unbedeutend. Diese Computer sind reguläre Arbeitsplätze, die für Web-Surfen, E-Mail, Chatten, etc. verwendet werden, außer COMP3, welcher als kleiner Webserver läuft. Das interne Netzwerk verwendet den 192.168.0.0 / 255.255.255.0-Netzwerkblock.

Der OpenBSD-Router ist ein Pentium 100 mit zwei Netzwerkkarten: eine 3com 3c509B (ep0) und eine Intel EtherExpress Pro/100 (fxp0). Der Router hat eine ADSL-Verbindung zum Internet und verwendet NAT, um diese Verbindung mit dem internen Netzwerk zu teilen. Die IP-Adresse des externen Interfaces wird vom Internet-Provider dynamisch zugewiesen.

Das Ziel

Die Ziele sind:

Vorbereitung

Dieses Dokument nimmt an, dass der OpenBSD-Host ordentlich konfiguriert wurde, so dass er als Router funktioniert, einschließlich der Überprüfung der IP-Netzwerk-Einstellungen, Internetverbindung und dass net.inet.ip.forwarding auf ,1' eingestellt wurde.

Der Regelsatz

Das nächste Kapitel wird Schritt für Schritt durch einen Regelsatz gehen, der die zuvor genannten Ziele erreichen wird.

Makros

Die folgenden Makros wurden definiert, um die Wartung und das Lesen des Regelsatzes einfacher zu machen:
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 }"

comp3 = "192.168.0.3"

Die ersten beiden Zeilen definieren das Netzwerk-Interface, auf dem das Filtern stattfinden wird. Die dritte und vierte Zeile listen die TCP-Portnummern der Dienste auf, die dem Internet gegenüber offengelegt werden (SSH und ident/auth) und den ICMP-Pakettyp, dem erlaubt wird, die Firewall-Maschine zu erreichen. Die fünfte Zeile definiert das Loopback und die RFC 1918-Adressblöcke. Und zum Schluss definiert die letzte Zeile die IP-Adresse von COMP3.

Hinweis: Wenn die ADSL-Internetverbindung PPPoE benötigt, dann werden Filter und NAT auf dem tun0-Interface stattfinden und nicht auf ep0.

Optionen

Die folgenden beiden Optionen werden die standardmäßige Antwort für block-Filterregeln setzen und Statistik-Aufzeichnungen für das externe Interface anstellen:
set block-policy return
set loginterface $ext_if

Jedes Unix-System hat ein sogenanntes Loopbackinterface. Hierbei handelt es sich um ein virtuelles Netzwerkinterface, das von Applikationen genutzt wird, um mit anderen auf dem gleichen System zu kommunizieren. Unter OpenBSD ist das Loopbackinterface lo(4). Es ist allgemein gute Praxis, jegliches Filtern auf den Loopbackinterfaces zu unterbinden. Die Verwendung von set skip bewerkstelligt dies.

set skip on lo0

Scrub

Es gibt keinen Grund, das empfohlene ,scrubbing', das auf den gesamten eingehenden Verkehr angewandt wird, nicht zu verwenden, so dass dies ein einfacher Einzeiler ist:
scrub in all

Network Address Translation

Um NAT auf das gesamte interne Netzwerk durchzuführen, wird folgende nat-Regel verwendet:
nat on $ext_if from $int_if:network to any -> ($ext_if)

Da die IP-Adresse des externen Interfaces dynamisch zugewiesen wird, werden Klammern um das Übersetzungs-Interface herum gesetzt, so dass PF bemerken wird, wenn die Adresse sich ändert.

Umleitung

Die erste benötigte Umleitungs-Regel ist für ftp-proxy(8), so dass sich FTP-Clients vom lokalen Netzwerk aus auf FTP-Server im Internet verbinden können.
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021

Bedenke, dass diese Regel nur FTP-Verbindungen auf Port 21 erfasst wird. Wenn sich Benutzer auf regulärer Basis auf FTP-Server auf anderen Ports verbinden, sollte eine Liste verwendet werden, die die Ziel-Ports angibt, zum Beispiel: from any to any port { 21, 2121 }.

Die zweite Umleitungs-Regel erfasst alle Versuche von Personen im Internet, die auf den TCP-Port 80 der Firewall verbinden wollen. Berechtigte Versuche, diesen Port zu erreichen, werden von Benutzern sein, die versuchen, den Webserver vom Netzwerk zu erreichen. Dieser Verbindungsversuch muss auf COMP3 weitergeleitet werden:

rdr on $ext_if proto tcp from any to any port 80 -> $comp3

Filter-Regeln

Nun die Filterregeln. Fange mit standardmäßigem Blocken an:
block all

Zu diesem Zeitpunkt wird nichts durch die Firewall gelassen, nicht einmal vom internen Netzwerk. Die folgenden Regeln werden die Firewall, den oben genannten Zielen entsprechend, öffnen, so wie alle benötigten virtuellen Interfaces.

Als nächstes werden die RFC 1918-Adressen geblockt, wenn sie vom externen Interface herkommen. Diese Adressen sollten niemals im öffentlichen Internet auftauchen, und das Herausfiltern stellt sicher, dass der Router diese nicht aus dem internen Netzwerk aus "auslaufen" (,leak') lässt und blockt ebenfalls jegliche eingehenden Pakete mit einer Quell-Adresse, die aus einem dieser Netzwerke kommt.

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

Bedenke, dass blockdrop verwendet wird, um PF zu sagen, dass nicht mit einem TCP-RST- oder ICMP-Unreachable-Paket geantwortet soll. Da die RFC-1918-Adressen im Internet nicht existieren, werden jegliche Pakete, die dorthin gesendet werden, niemals ankommen. Die quick-Option wird benutzt, um PF zu sagen, dass der Rest der Filterregeln nicht berücksichtigt werden soll, wenn eine der vorherigen Regeln zutrifft; Pakete zu oder von den $priv_nets-Netzwerken unverzüglich fallen lassen.

Nun öffne die Ports, die von den Netzwerkdiensten genutzt werden, die für das Internet verfügbar sein sollen:

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

Die Netzwerk-Ports in dem Makro $tcp_services anzugeben, macht es simpel, zusätzliche Dienste dem Internet anzubieten, indem diese in dem Makro eingetragen werden und der Regelsatz neugeladen wird. UDP-Dienste können ebenfalls geöffnet werden, indem ein $udp_services-Makro erstellt wird und eine Filterregel so wie oben angegeben hinzugefügt wird, die proto udp angibt.

Zusätzlich zur rdr-Regel, die den Webserver-Verkehr zu COMP3 weiterleitet, MÜSSEN wir ebenfalls diesen Verkehr durch die Firewall leiten:

pass in on $ext_if proto tcp from any to $comp3 port 80 \
    flags S/SA synproxy state

Für ein bisschen mehr Sicherheit werden wir den TCP-SYN-Proxy verwenden, um den Webserver noch besser zu beschützen.

Damit wir in der Lage sind, aktive FTP-Verbindungen vom LAN aus nutzen zu können, muss folgende Regel vorhanden sein, die die ftp-data-Verbindung, die vom FTP Server eingeleitet wurde, zurück zum Client lässt. Da FTP-Verbindungen wegen ftp-proxy durch einen Proxy laufen, wird die ftp-data-Verbindung tatsächlich angenommen, so dass die Daten zum Client im LAN weitergeleitet werden.

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

ICMP-Verkehr muss nun durchgelassen werden:

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

Dem $tcp_services-Makro ähnlich, kann der $icmp_types-Makro einfach editiert werden, um die Typen der ICMP-Pakete zu ändern, denen erlaubt wird, die Firewall zu erreichen. Bedenke, dass diese Regel auf alle Netzwerk-Interfaces zutrifft.

Nun muss der Verkehr zu und vom internen Netzwerk zugelassen werden. Wir nehmen an, dass die Benutzer im internen Netzwerk wissen, was sie tun und keinen Ärger verursachen werden. Dies ist nicht notwendigerweise eine gültige Annahme; ein sehr viel restriktiverer Regelsatz wäre für bestimmte Umgebungen angebrachter.

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

Die gerade genannte Regel wird jeglichen internen Maschinen erlauben, Pakete durch die Firewall zu senden; jedoch wird sie der Firewall nicht erlauben, eine Verbindung zu internen Maschinen aufzubauen. Ist das eine gute Idee? Das kommt auf die genaueren Details des Netzwerkaufbaus an. Wenn die Firewall ebenfalls ein DHCP-Server ist, muss sie eventuell erst eine Adresse ,anpingen', um ihre Verfügbarkeit sicherzustellen, bevor sie zugewiesen wird. Der Firewall zu erlauben, eine Verbindung in das interne Netzwerk aufbauen zu können, ermöglicht es jemanden, der mit ssh auf die Firewall vom Internet aus zugegriffen hat, auf Maschinen im internen Netzwerk zuzugreifen. Behalte aber im Hinterkopf, dass es kein großer Sicherheitsvorteil ist, wenn man der Firewall nicht die Möglichkeit gibt, direkt mit dem Netzwerk zu kommunizieren; wenn jemand Zugriff auf die Firewall erhält, könnte es eventuell sein, dass dieser die Filterregeln sowieso ändert. Durch das Hinzufügen dieser Regel wird die Firewall in der Lage sein, Verbindungen ins interne Netzwerk aufzubauen:

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

Bedenke, dass, wenn beide Zeilen vorhanden sind, die keep state-Option nicht benötigt wird; alle Pakete werden in der Lage sein, das interne Interface zu passieren, da hier eine Regel ist, die Pakete in beide Richtungen durchlässt. Trotz allem, wenn die pass out-Zeile nicht mit eingebunden ist, muss die pass in-Zeile keep state mit einbinden. Es gibt sogar einen Leistungsbonus, wenn man ,keep state' verwendet: ,State'-Tabellen werden verarbeitet, bevor die Regeln überprüft werden, und wenn eine ,state'-Übereintreffung gefunden wird, wird das Paket durch die Firewall gelassen, ohne dass die Regelsatzüberprüfung durchlaufen werden muss, obwohl solch ein einfaches System wahrscheinlich nicht genug Last aufbringen wird, als dass es einen Unterschied machen könnte.

Schlussendlich muss der Verkehr aus dem externen Interface gelassen werden:

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

TCP-, UDP- und ICMP-Verkehr darf die Firewall in Richtung Internet verlassen. ,State'-Informationen werden aufbewahrt, so dass die wiederkommenden Pakete durch die Firewall gelassen werden.

Der komplette Regelsatz

# makros
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 }"
	  
comp3 = "192.168.0.3"

# optionen
set block-policy return
set loginterface $ext_if
set skip on lo0

# 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
rdr on $ext_if proto tcp from any to any port 80 -> $comp3

# filterregeln
block 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 on $ext_if proto tcp from any to $comp3 port 80 \
   flags S/SA synproxy state

pass in on $ext_if inet proto tcp from port 20 to ($ext_if) \
   user proxy 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

[Zurück: Firewal-Redundanz mit CARP und pfsync] [Inhalt]


[zurück] www@openbsd.org
$OpenBSD: example1.html,v 1.12 2006/04/25 08:25:49 saad Exp $