Nächste Seite: Wichtige Portnummern
Aufwärts: Crashkurs Firewallaufbau unter Linux
Vorherige Seite: Die Firewall als Router
  Inhalt
Unterabschnitte
Um die Komplexität des Aufbaus einer Firewall mit DMZ am Stück darzustellen,
werden wir in diesem Kapitel eine komplette solche Firewall aufbauen.
Zunächst einmal aber noch etwas Begriffsklärung für das Projekt:
- Bastion
- Der Rechner, der das Internet mit der DMZ verbindet.
- Choke
- Der Rechner, der das zu schützende Netz mit der DMZ verbindet.
- DMZ
- Die demilitarisierte Zone, das Netz zwischen dem Internet und dem
zu schützenden Netz.
- LAN
- Das zu schützende Netz.
Wir gehen also davon aus, daß Bastion und Choke beide als Gateway (dual
homed host) zur DMZ dienen. Die DMZ enthält öffentliche und halböffentliche
Server. Jedes Netzwerkinterface der beiden Firewall-Rechner (Bastion und
Choke) besitzt eigene, individuelle Regeln. Wir benötigen also mindestens
vier Regelsätze, je einen für das externe und interne Interface beider
Maschinen. Die Regeln für das externe Interface der Bastion sind fast
identisch mit denen aus dem Beispiel aus dem Abschnitt 6.4 (Seite
).
Die wirklichen Neuigkeiten dieses Kapitels beziehen sich hauptsächlich auf
die Schnittstellen zur DMZ, also die interne Schnittstelle der Bastion und
die externe Schnittstelle der Choke. Diese Regeln verhalten sich
spiegelbildlich zueinander. Für die öffentlichen Server innerhalb der DMZ
muß es noch ein paar separate Regeln geben, wir gehen aber in diesem
Beispiel davon aus, daß es sich hierbei um spezialisierte Rechner handelt,
die jeweils nur einen Dienst anbieten und daher sehr einfache Regeln
benötigen.
Um den Rahmen und die Übersicht über dieses Kapitel nicht zu gefährden,
werden innerhalb des Kapitels Vereinfachungen zugelassen. Weil die externen
Regeln der Bastion praktisch identisch sind mit denen aus Abschnitt
6.4, werden hier nur die Unterschiede dargestellt. Im Anhang ab
Seite
sind die beiden Scripts für Bastion und Choke jedoch
beide noch einmal vollständig abgedruckt.
Bild 8..1: Der Aufbau des Beispiels
Das externe Interface der Bastion liegt auf der Schnittstelle eth0 und
hat die echte IP-Adresse 123.45.67.89 zugewiesen. Das interne Interface
liegt auf eth1 und hat die reservierte Adresse 192.168.1.1
Die DMZ hat die 192.168.1.0 als Netzwerkadresse.
Die Choke hat ihr externes Netz am Interface eth0 und dort die Adresse
192.168.1.2, ihr internes Netz liegt auf eth1 und bekommt die Adresse
192.168.5.1
Das LAN hat die Netzadresse 192.168.5.0 als Netzwerkadresse.
Ein Firewallscript lässt sich grundsätzlich leichter lesen und hauptsächlich
flexibler an Veränderungen anpassen, wenn wir nicht bei jeder Regel erneut
die IP-Adressen angeben, sondern am Anfang symbolische Konstanten
definieren, die wir im weiteren Verlauf dann benutzen. Das ist immer das
erste, was beim Aufbau neuer Scripts zu beachten ist und daher halten wir
uns an diese Vorgaben:
# Konstantendefinition
EXTERNAL_INTERFACE=eth0 # Das Interface ins Internet
IPADDR=123.45.67.89 # Adresse des Internetzugangs
MY_ISP=123.45.67.90/16 # Der Bereich meines Providers
BASTION_DMZ_INTERFACE=eth1 # internes Interface
BASTION_DMZ_IPADDR=192.168.1.1 # Adresse dazu
LOOPBACK_INTERFACE=lo # Local Loopback
LOOPBACK=127.0.0.0/8 # Loopback-Adressbereich
CHOKE_DMZ_IPADDR=192.168.1.2 # ext. Interface der Choke
DMZ_ADDRESSES=192.168.1.0/24 # IP-Bereich der DMZ
DMZ_BROADCAST=192.168.1.255 # Broadcastadresse DMZ
ANYWHERE=any/0 # Jede IP-Adresse
CLASS_A=10.0.0.0/8 # Reservierter Bereich Klasse A
CLASS_B=172.16.0.0/12 # Reservierter Bereich Klasse B
CLASS_C=192.168.0.0/16 # Reservierter Bereich Klasse C
CLASS_D=224.0.0.0/4 # Komplette Klasse D
CLASS_E=240.0.0.0/5 # Komplette Klasse E
BROADCAST_SRC=0.0.0.0 # Broadcast Absender
BROADCAST_DEST=255.255.255.255 # Broadcast Empfänger
PRIVPORTS=0:1023 # Privilegierte Portnummern
UNPRIVPORTS=1024:65535 # Unprivilegierte Portnummern
#Konstantendefinition
CHOKE_DMZ_INTERFACE=eth0 # externes Interface der Choke
CHOKE_DMZ_IPADDR=192.168.1.2 # externe Adresse der Choke
CHOKE_LAN_INTERFACE=eth1 # internes Interface der Choke
CHOKE_LAN_IPADDR=192.168.5.1 # interne Adresse der Choke
LOOPBACK_INTERFACE=lo # Local Loopback
LOOPBACK=127.0.0.0/8 # Loopback-Adressbereich
BASTION_DMZ_IPADDR=192.168.1.1 # interne Adresse der Bastion
DMZ_ADDRESSES=192.168.1.0/24 # IP-Bereich der DMZ
LAN_ADDRESSES=192.168.5.0/24 # IP-Bereich des LAN
DMZ_BROADCAST=192.168.1.255 # Broadcastadresse DMZ
ANYWHERE=any/0 # Jede IP-Adresse
CLASS_A=10.0.0.0/8 # Reservierter Bereich Klasse A
CLASS_B=172.16.0.0/12 # Reservierter Bereich Klasse B
CLASS_C=192.168.0.0/16 # Reservierter Bereich Klasse C
CLASS_D=224.0.0.0/4 # Komplette Klasse D
CLASS_E=240.0.0.0/5 # Komplette Klasse E
BROADCAST_SRC=0.0.0.0 # Broadcast Absender
BROADCAST_DEST=255.255.255.255 # Broadcast Empfänger
PRIVPORTS=0:1023 # Privilegierte Portnummern
UNPRIVPORTS=1024:65535 # Unprivilegierte Portnummern
Wie üblich löschen wir zunächst einmal in beiden Scripts (für Choke und
Bastion) die bisher bestehenden Regeln. Das ist nur eine
Sicherheitsmaßnahme, um zu vermeiden, daß eventuell existierende Regeln, die
vor dem Aufruf des Scripts erstellt wurden, nicht weiter gelten. In beiden
Scripts steht also jetzt
# Alle bestehenden Regeln löschen
ipchains -F
Die Chains sind jetzt gelöscht, nicht jedoch eine eventuell bestehende
Policy. Also definieren wir sofort eine neue, die alles grundsätzlich
verbietet, was nicht explizit erlaubt ist. Hier machen wir aber einen
Unterschied zwischen Bastion und Choke. Die Bastion arbeitet grundsätzlich
mit DENY, gibt also keinerlei Rückmeldungen zurück, außer ins interne Netz,
also die DMZ. Das ist wichtig, weil solche Rückmeldungen einem potenziellen
Angreifer schon bestimmte Dinge mitteilen kann. Die Choke jedoch arbeitet in
einem Umfeld, das wesentlich mehr Vertrauen von uns verdient. Hier arbeiten
wir mit REJECT, um Fehlermeldungen zu erzeugen und Timeout-Wartezeiten
dadurch zu vermeiden. Das Script der Bastion erhält also folgenden Eintrag:
# Voreingestellte Policies setzen
ipchains -P input DENY
ipchains -P output REJECT
ipchains -P forward REJECT
während die Choke überall mit REJECT arbeitet:
# Voreingestellte Policies setzen
ipchains -P input REJECT
ipchains -P output REJECT
ipchains -P forward REJECT
An diesem Punkt sind alle Regeln gelöscht und alle Policies auf DENY oder
REJECT gesetzt. Es ist keinerlei Netzverkehr mehr möglich.
Wie im letzten Beispiel sollten wir jetzt zunächst wieder das
Loopback-Device ermöglichen, dort sind Angriffe nicht möglich, es droht
keinerlei Gefahr, wir lassen einfach alles auf diesem Device zu. Das gilt
wieder für beide Maschinen, Bastion und Choke:
# Loopback ohne Einschränkungen
ipchains -A input -i $LOOPBACK_INTERFACE -j ACCEPT
ipchains -A output -i $LOOPBACK_INTERFACE -j ACCEPT
Es kann auch nicht schaden, wenn wir an dieser Stelle wieder bei beiden
Maschinen die Kernel-eigenen Schutzroutinen aktivieren, wie wir das auch
schon im Abschnitt 6.4.2 gemacht hatten. Dort ist es schon erklärt,
daher hier nur noch die entsprechenden Anweisungen:
# SYN_COOKIES aktivieren
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
# SOURCE ADDRESS VERIFICATION aktivieren
for i in /proc/sys/net/ipv4/conf/*/rp_filter
do
echo 1 > $i
done
Jetzt filtern wir wieder die Adressen aus, die offensichtlich ungültig sind.
Zunächst mal wieder jeweils die eigenen Adressen. Die Bastion Firewall
bekommt also die Anweisungen
# Pakete ablehnen, die vorgeben von der eigenen Adresse zu stammen
ipchains -A input -i $EXTERNAL_INTERFACE \
-s $IPADDR -j DENY -l
ipchains -A input -i $BASTION_DMZ_INTERFACE \
-s $BASTION_DMZ_IPADDR -j DENY -l
während die Choke folgende Zeilen braucht:
# Pakete ablehnen, die vorgeben von der eigenen Adresse zu stammen
ipchains -A input -i $CHOKE_LAN_INTERFACE\
-s $CHOKE_LAN_IPADDR -j REJECT -l
ipchains -A input -i CHOKE_DMZ_INTERFACE \
-s $CHOKE_DMZ_IPADDR -j REJECT -l
Bei der Bastion belassen wir die Filterung der restlichen Adressen wie in
unserem Beispiel aus Abschnitt 6.4. Die Choke hingegen muß nur
Adressen aus dem Pool der reservierten A- und B-Klassen aussondern, weil
sie ja selbst auf beiden Netzwerkkarten eine C-Klasse reservierte Adresse
benutzt. Nebenbei filtern wir wie gehabt auch Loopback- und fehlerhafte
Broadcasts aus. Die Angabe der von der IANA reservierten Adressen sparen wir
uns für die Choke, die Bation hat sie ja schon.
# Pakete mit privaten A-Klasse Adressen als Sender oder
# Empfänger verwerfen
ipchains -A input -i $CHOKE_DMZ_INTERFACE -s $CLASS_A -j REJECT -l
ipchains -A input -i $CHOKE_LAN_INTERFACE -s $CLASS_A -j REJECT -l
ipchains -A output -i $CHOKE_DMZ_INTERFACE -d $CLASS_A -j REJECT -l
ipchains -A output -i $CHOKE_LAN_INTERFACE -d $CLASS_A -j REJECT -l
# Pakete mit privaten B-Klasse Adressen als Sender oder
# Empfänger verwerfen
ipchains -A input -i $CHOKE_DMZ_INTERFACE -s $CLASS_B -j REJECT -l
ipchains -A input -i $CHOKE_LAN_INTERFACE -s $CLASS_B -j REJECT -l
ipchains -A output -i $CHOKE_DMZ_INTERFACE -d $CLASS_B -j REJECT -l
ipchains -A output -i $CHOKE_LAN_INTERFACE -d $CLASS_B -j REJECT -l
# Pakete mit D-Klasse Adressen als Sender verwerfen
ipchains -A input -i $CHOKE_DMZ_INTERFACE -s $CLASS_D -j REJECT -l
ipchains -A input -i $CHOKE_LAN_INTERFACE -s $CLASS_D -j REJECT -l
ipchains -A output -i $CHOKE_DMZ_INTERFACE -s $CLASS_D -j REJECT -l
ipchains -A output -i $CHOKE_LAN_INTERFACE -s $CLASS_D -j REJECT -l
# Pakete mit E-Klasse Adressen verwerfen
ipchains -A input -i $CHOKE_DMZ_INTERFACE -s $CLASS_E -j REJECT -l
ipchains -A input -i $CHOKE_LAN_INTERFACE -s $CLASS_E -j REJECT -l
# Pakete mit Loopback Adressen als Sender verwerfen
ipchains -A input -i $CHOKE_DMZ_INTERFACE -s $LOOPBACK -j REJECT -l
ipchains -A input -i $CHOKE_LAN_INTERFACE -s $LOOPBACK -j REJECT -l
# Pakete mit fehlerhaften Broadcast Adressen verwerfen
ipchains -A input -i $CHOKE_DMZ_INTERFACE \
-s $BROADCAST_DEST -j REJECT -l
ipchains -A input -i $CHOKE_LAN_INTERFACE \
-s $BROADCAST_DEST -j REJECT -l
ipchains -A input -i $CHOKE_DMZ_INTERFACE \
-d $BROADCAST_SRC -j REJECT -l
ipchains -A input -i $CHOKE_LAN_INTERFACE \
-d $BROADCAST_SRC -j REJECT -l
Damit hätten wir die Grundeinstellung bei beiden Scripts erledigt. Jetzt
geht es an die eigentliche Arbeit, verspricht aber auch interessanter zu
werden.
Die Bastion hat schon Regeln für ICMP-Nachrichten, die sich bisher aber nur
auf die externe Schnittstelle, also auf die Schnittstelle ins Internet
beziehen. Diese Regeln lassen wir wie gehabt, fügen aber noch ein paar
Regeln für die Kommunukation mit der DMZ hinzu. Hier wird das erste Mal die
Symetrie zwischen dem internen Interface der Bastion und dem externen der
Choke sichtbar.
Die ICMP-Nachrichten vom Typ 4 (source-quench) werden erstellt, wenn
ein Kommunikationspartner mit der Geschwindigkeit eines anderen nicht mehr
mithalten kann, weil z.B. seine internen Buffer voll sind. Bastion und Choke
akzeptieren alle source-quench Nachrichten, die bei der Kommunikation
mit der DMZ entstehen.
# source-quench zur DMZ
ipchains -A output -i $BASTION_DMZ_INTERFACE -p icmp\
-s $BASTION_DMZ_IPADDR 4 -d $DMZ_ADDRESSES -j ACCEPT
ipchains -A input -i $BASTION_DMZ_INTERFACE -p icmp\
-s $DMZ_ADDRESSES 4 -d $BASTION_DMZ_IPADDR -j ACCEPT
# source-quench zur DMZ
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $DMZ_ADDRESSES 4 -d $CHOKE_DMZ_IPADDR -j ACCEPT
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $CHOKE_DMZ_IPADDR 4 -d $DMZ_ADDRESSES -j ACCEPT
Sichtbar wird hier, daß die Regeln für Bastion und Choke sehr ähnlich sind,
aber eben nur die für die interne Bastion Schnittstelle und die der externen
Choke Schnittstelle. Das ist logisch, denn diese beiden Schnittstellen
transportieren ja die Informationspakete vom LAN ins Internet.
Diese Nachrichtenpakete (Typ 12) werden gesendet, wenn ein Paket empfangen wurde, das
ungültige Daten im Header aufweist. Auch diese Nachrichten lassen wir für
die Kommunikation mit der DMZ grundsätzlich durch.
# parameter-problem zur DMZ
ipchains -A output -i $BASTION_DMZ_INTERFACE -p icmp\
-s $ANYWHERE 12 -d $DMZ_ADDRESSES -j ACCEPT
ipchains -A input -i $BASTION_DMZ_INTERFACE -p icmp\
-s $DMZ_ADDRESSES 12 -d $ANYWHERE -j ACCEPT
# parameter-problem zur DMZ
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $ANYWHERE 12 -d $CHOKE_DMZ_IPADDR -j ACCEPT
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $CHOKE_DMZ_IPADDR 12 -d $ANYWHERE -j ACCEPT
Dieser Nachrichtenpakettyp (Typ 3) ist eine allgemeine Fehlermeldung.
Auch diese Nachrichten lassen wir für
die Kommunikation mit der DMZ grundsätzlich durch.
# destination-unreachable zur DMZ
ipchains -A output -i $BASTION_DMZ_INTERFACE -p icmp\
-s $ANYWHERE 3 -d $DMZ_ADDRESSES -j ACCEPT
ipchains -A input -i $BASTION_DMZ_INTERFACE -p icmp\
-s $DMZ_ADDRESSES 3 -d $ANYWHERE -j ACCEPT
# destination-unreachable zur DMZ
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $ANYWHERE 3 -d $CHOKE_DMZ_IPADDR -j ACCEPT
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $CHOKE_DMZ_IPADDR 3 -d $ANYWHERE -j ACCEPT
Diese Nachrichtenpakete (Typ 11) zeigen an, daß ein Paket zu oft geroutet
wurde, daß seine Lebensdauer auf 0 gesunken ist. Es wird aber auch als
Antwort für Traceroute benutzt.
Auch diese Nachrichten lassen wir für
die Kommunikation mit der DMZ grundsätzlich durch.
# time-exceeded zur DMZ
ipchains -A output -i $BASTION_DMZ_INTERFACE -p icmp\
-s $BASTION_DMZ_IPADDR 11 -d $DMZ_ADDRESSES -j ACCEPT
ipchains -A input -i $BASTION_DMZ_INTERFACE -p icmp\
-s $DMZ_ADDRESSES 11 -d $BASTION_DMZ_IPADDR -j ACCEPT
Die Choke darf nur mit der Bastion Nachrichten vom Typ time-exceed
austauschen.
# time-exceeded zur DMZ
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $BASTION_DMZ_IPADDR 11 -d $CHOKE_DMZ_IPADDR -j ACCEPT
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $CHOKE_DMZ_IPADDR 11 -d $BASTION_DMZ_IPADDR -j ACCEPT
Der Befehl ping verwendet zwei unterschiedliche Nachrichtentypen,
jeweils für Anfragen (echo-request - Typ 8) und Antworten (echo-reply - Typ 0).
Alle Rechner der DMZ dürfen ins Internet pingen:
# Ausgehendes Ping aus der DMZ
ipchains -A input -i $BASTION_DMZ_INTERFACE -p icmp\
-s $DMZ_ADDRESSES 8 -d $ANYWHERE -j ACCEPT
ipchains -A output -i $BASTION_DMZ_INTERFACE -p icmp\
-s $ANYWHERE 0 -d $DMZ_ADDRESSES -j ACCEPT
Andersherum darf aber nur die Bastion selbst Rechner in der DMZ anpingen:
# Ankommendes Ping in die DMZ
ipchains -A output -i $BASTION_DMZ_INTERFACE -p icmp\
-s $BASTION_DMZ_IPADDR 8 -d $DMZ_ADDRESSES -j ACCEPT
ipchains -A input -i $BASTION_DMZ_INTERFACE -p icmp\
-s $DMZ_ADDRESSES 0 -d $BASTION_DMZ_IPADDR -j ACCEPT
Die Choke darf jeden Rechner im Internet anpingen:
# Ausgehendes Ping ins Internet
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $CHOKE_DMZ_IPADDR 8 -d $ANYWHERE -j ACCEPT
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $ANYWHERE 0 -d $CHOKE_DMZ_IPADDR -j ACCEPT
Ankommende Pings sind jedoch nur aus der DMZ gestattet.
# Ankommende Pings aus der DMZ
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $DMZ_ADDRESSES 8 -d $CHOKE_DMZ_IPADDR -j ACCEPT
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p icmp\
-s $CHOKE_DMZ_IPADDR 0 -d $DMZ_ADDRESSES -j ACCEPT
Die Dienste auf den unprivilegierten Ports lassen wir auf der Bastion so,
wie wir sie im Abschnitt 6.4 formuliert hatte. Die Choke muß
diese Dienste überhaupt nicht beachten, denn es waren ja nur Verbote aus dem
globalen Netz. Von außen droht uns also keine Gefahr mehr.
Wir brauchen diese Dienste nicht vom LAN in die DMZ
weitergeben und da grundsätzlich alles verboten ist, was nicht explizit
erlaubt, benötigen wir keine Regeln mehr. Innerhalb des LAN stehen sie uns
natürlich weiter zur Verfügung. Dort werden Pakete ja nicht gefiltert,
sondern nur weitergegeben.
Das DNS-System (TCP- und UDP-Port 53) ist heute für eine Zugriff auf das
Internet von zwingender Bedeutung. Ohne Nameserver müssten die IP-Addressen
der einzelnen Server im Internet bekannt sein, das ist mehr oder weniger
unmöglich. Alle Rechner des LAN müssen also Zugriff auf einen Nameserver
haben. Dabei gibt es aber verschiedene Möglichkeiten, die hier kurz
beschrieben werden sollen.
Die einfachste Form ist die, daß ein öffentlicher Nameserver im Internet,
etwa der Ihres Providers benutzt wird. In diesem Fall muß der Choke nur
mitgeteilt werden, daß DNS-Anfragen durchgelassen werden, so wie wir das
auch schon im Beispiel in Abschnitt 6.4 getan haben. Die Bastion
behält die Zeilen aus dem genannten Beispiel ebenfalls. Damit ist ein
Durchgang geschaffen, der alle notwendigen DNS-Dienste ermöglicht. Die
Choke erhält also die Zeilen:
# DNS IP Adresse:
NAMESERVER=xx.xx.xx.xx
# UDP-Nameserverzugriff
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p udp\
-s $CHOKE_DMZ_IPADDR $UNPRIVPORTS \
-d $NAMESERVER 53 -j ACCEPT
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p udp\
-s $NAMESERVER 53 \
-d $CHOKE_DMZ_IPADDR $UNPRIVPORTS -j ACCEPT
# TCP-Nameserverzugriff
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p tcp\
-s $CHOKE_DMZ_IPADDR $UNPRIVPORTS \
-d $NAMESERVER 53 -j ACCEPT
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p tcp ! -y\
-s $NAMESERVER 53 \
-d $CHOKE_DMZ_IPADDR $UNPRIVPORTS -j ACCEPT
Wir werden ja später das Masquerading aktivieren, daher reicht es, wenn die
Adresse immer nur die der Choke ist. Alle Adressen des LAN werden ja in
diese Adresse maskiert.
Ein wesentlich komplexeres Verfahren besteht darin, eigene Nameserver zu
betreiben. In unserem Beispiel würde sich dabei - wenn hohe Sicherheit
erwünscht ist - folgendes Szenario anbieten:
Auf der Bastion läuft ein öffentlicher Nameserver. Er ist konfiguriert als
autoritativer Server für die Site, verfügt aber nur über unvollständige
Daten. Er hat keine Informationen über die Rechner des LAN, nur über die der
DMZ. Die Programme der Bastion selbst greifen nicht auf diesen Server
zu.
Auf der Choke läuft auch ein Nameserver. Dieser Nameserver enthält
tatsächlich die realen Daten des LAN und der DMZ. Alle Clients aus dem LAN
greifen ausschließlich auf diesen Nameserver zu. Auch die Clients der
Bastion (die Programme der Bastion, die einen DNS-Dienst benötigen) greifen
auf den Server der Choke zu. Wenn der Choke-Server eine Anfrage nicht
beantworten kann, leitet er sie weiter an den Server der Bastion, der sie
wiederum an einen externen Server im Internet weitergibt.
Für diese Konfiguration sind natürlich auch erheblich komplexere Regeln
notwendig.
# Der DNS-Server der Bastion akzeptiert Anfragen der Choke (UDP 53)
ipchains -A input -i $BASTION_DMZ_INTERFACE -p udp\
-s $CHOKE_DMZ_IPADDR 53\
-d $BASTION_DMZ_IPADDR 53 -j ACCEPT
ipchains -A output -i $BASTION_DMZ_INTERFACE -p udp\
-s $BASTION_DMZ_IPADDR 53\
-d $CHOKE_DMZ_IPADDR 53 -j ACCEPT
# DNS Anfragen der Bastion an den Server der Choke (UDP/TCP 53)
ipchains -A output -i $BASTION_DMZ_INTERFACE -p udp\
-s $BASTION_DMZ_IPADDR $UNPRIVPORTS \
-d $CHOKE_DMZ_IPADDR 53 -j ACCEPT
ipchains -A input -i $BASTION_DMZ_INTERFACE -p udp\
-s $CHOKE_DMZ_IPADDR 53 \
-d $BASTION_DMZ_IPADDR $UNPRIVPORTS -j ACCEPT
ipchains -A output -i $BASTION_DMZ_INTERFACE -p tcp\
-s $BASTION_DMZ_IPADDR $UNPRIVPORTS \
-d $CHOKE_DMZ_IPADDR 53 -j ACCEPT
ipchains -A input -i $BASTION_DMZ_INTERFACE -p tcp ! -y\
-s $CHOKE_DMZ_IPADDR 53 \
-d $BASTION_DMZ_IPADDR $UNPRIVPORTS -j ACCEPT
# DNS IP Adresse (Nameserver im Internet):
NAMESERVER=xx.xx.xx.xx
#DNS Forwarding (Server zu Server)
ipchains -A output -i $EXTERNAL_INTERFACE -p udp\
-s $IPADDR 53 \
-d $NAMESERVER 53 -j ACCEPT
ipchains -A input -i $EXTERNAL_INTERFACE -p udp\
-s $NAMESERVER 53 \
-d $IPADDR 53 -j ACCEPT
# UDP-Nameserverzugriff
ipchains -A output -i $EXTERNAL_INTERFACE -p udp\
-s $IPADDR $UNPRIVPORTS \
-d $ANYWHERE 53 -j ACCEPT
ipchains -A input -i $EXTERNAL_INTERFACE -p udp\
-s $ANYWHERE 53 \
-d $IPADDR $UNPRIVPORTS -j ACCEPT
# TCP-Nameserverzugriff
ipchains -A output -i $EXTERNAL_INTERFACE -p tcp\
-s $IPADDR $UNPRIVPORTS \
-d $ANYWHERE 53 -j ACCEPT
ipchains -A input -i $EXTERNAL_INTERFACE -p tcp ! -y\
-s $ANYWHERE 53 \
-d $IPADDR $UNPRIVPORTS -j ACCEPT
# DNS Zugriff fremder Clients
ipchains -A input -i $EXTERNAL_INTERFACE -p udp\
-s $ANYWHERE $UNPRIVPORTS\
-d $IPADDR 53 -j ACCEPT
ipchains -A output -i $EXTERNAL_INTERFACE -p udp\
-s $IPADDR 53\
-d $ANYWHERE $UNPRIVPORTS -j ACCEPT
ipchains -A input -i $EXTERNAL_INTERFACE -p tcp\
-s $ANYWHERE $UNPRIVPORTS\
-d $IPADDR 53 -j ACCEPT
ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y\
-s $IPADDR 53\
-d $ANYWHERE $UNPRIVPORTS -j ACCEPT
Der private Nameserver liegt auf der Choke. Clients aus dem LAN und der
Bastion greifen auf diesen Server zu. Wenn er eine Anfrage nicht beantworten
kann, dann leitet er sie an den Server der Bastion weiter.
Die Regeln für die Choke verhalten sich gewissermaßen spiegelbildlich zu
denen der Bastion.
# Der DNS-Server der Choke gibt Anfragen an die Bastion (UDP 53)
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p udp\
-s $CHOKE_DMZ_IPADDR 53\
-d $BASTION_DMZ_IPADDR 53 -j ACCEPT
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p udp\
-s $BASTION_DMZ_IPADDR 53\
-d $CHOKE_DMZ_IPADDR 53 -j ACCEPT
# Der Nameserver der Choke lässt Anfragen aller Clients aus der
# DMZ zu (TCP/UDP 53)
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p udp \
-s $DMZ_ADDRESSES $UNPRIVPORTS \
-d $CHOKE_DMZ_IPADDR 53 -j ACCEPT
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p udp \
-s CHOKE_DMZ_IPADDR 53 \
-d $DMZ_ADDRESSES $UNPRIVPORTS -j ACCEPT
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p tcp \
-s $DMZ_ADDRESSES $UNPRIVPORTS \
-d $CHOKE_DMZ_IPADDR 53 -j ACCEPT
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p tcp ! -y \
-s CHOKE_DMZ_IPADDR 53 \
-d $DMZ_ADDRESSES $UNPRIVPORTS -j ACCEPT
Dieser Service (TCP 113) wird von manchen Internet-Diensten benutzt, um Namen oder ID
eines bestimmten Users zu erfragen. Das ist etwa bei fremden Mailservern der
Fall, die Mails weitergeben. Es ist nicht zwingend nötig, selbst einen
solchen Server laufen zu haben, obwohl nichts dagegen spricht. Auf jeden
Fall sollten wir eine Firewall-Regel erstellen, um unnötige Timeouts zu
vermeiden.
Für unser Beispiel werden wir davon ausgehen, daß sowohl auf der Bastion,
als auch auf der Choke sowohl Clients, als auch Server mit dem auth-Protokoll arbeiten.
# abgehende auth-Anfragen ins Internet
ipchains -A output -i $EXTERNAL_INTERFACE -p tcp\
-s $IPADDR $UNPRIVPORTS\
-d $ANYWHERE 113 -j ACCEPT
ipchains -A input -i $EXTERNAL_INTERFACE -p tcp ! -y\
-s $ANYWHERE 113 \
-d $IPADDR $UNPRIVPORTS -j ACCEPT
# ankommende auth-Anfragen aus dem Internet
ipchains -A input -i $EXTERNAL_INTERFACE -p tcp\
-s $ANYWHERE $UNPRIVPORTS\
-d $IPADDR 113 -j ACCEPT
ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y\
-s $IPADDR 113 \
-d $ANYWHERE $UNPRIVPORTS -j ACCEPT
# Bastion als auth-Client nach innen
ipchains -A output -i $BASTION_DMZ_INTERFACE -p tcp \
-s $BASTION_DMZ_IPADDR $UNPRIVPORTS \
-d $DMZ_ADDRESSES 113 -j ACCEPT
ipchains -A input -i $BASTION_DMZ_INTERFACE -p tcp ! -y\
-s $DMZ_ADDRESSES 113 \
-d $BASTION_DMZ_IPADDR $UNPRIVPORTS -j ACCEPT
# Bastion als Server nach innen
ipchains -A input -i $BASTION_DMZ_INTERFACE -p tcp \
-s $DMZ_ADDRESSES $UNPRIVPORTS \
-d $BASTION_DMZ_IPADDR 113 -j ACCEPT
ipchains -A output -i $BASTION_DMZ_INTERFACE -p tcp ! -y\
-s $BASTION_DMZ_IPADDR 113 \
-d $DMZ_ADDRESSES $UNPRIVPORTS -j ACCEPT
# Choke als auth Server
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p tcp \
-s $DMZ_ADDRESSES $UNPRIVPORTS \
-d $CHOKE_DMZ_IPADDR 113 -j ACCEPT
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p tcp ! -y\
-s $CHOKE_DMZ_IPADDR 113 \
-d $DMZ_ADDRESSES $UNPRIVPORTS -j ACCEPT
# Choke als auth-Client
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p tcp\
-s $CHOKE_DMZ_IPADDR $UNPRIVPORTS \
-d $ANYWHERE 113 -j ACCEPT
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p tcp ! -y \
-s $ANYWHERE 113 \
-d $CHOKE_DMZ_IPADDR $UNPRIVPORTS -j ACCEPT
Es gibt natürlich - auch nur für unser Modell - eine Vielzahl von
denkbaren Kombinationen für E-Mail Empfang und Versand. Wir werden hier
exemplarisch eine Kombination durchspielen, die wahrscheinlich in der Praxis
die häufigste ist. Die Bastion, die ja eine echte IP-Adresse hat, sendet
und empfängt Mail mit SMTP (TCP 25). Die Rechner des LAN holen sich die
Mails bei der Bastion mittels POP3 (TCP 110) ab.
Wir müssen also der Bastion erlauben SMTP-Pakete zu empfangen und zu
senden, und weiterhin POP-Anfragen zu empfangen und zu beantworten. Die
Choke muß auch SMTP durchlassen, schließlich senden die Rechner des LAN ihre
Mails ja mit SMTP. Sie muß ebenfalls POP-Pakete durchlassen, in beide
Richtungen.
Hier haben wir zunächst einmal zwei Möglichkeiten. Entweder wir schicken
alle ausgehende Mail an den Mailserver unseres Providers oder wir schicken
sie gleich an die entsprechenden Empfängerrechner. Die einfachere
Möglichkeit ist die des Providerservers, weil der sich dann um die korrekte
Weiterleitung kümmern muß. Die dazu nötigen Regeln der Bastion sind:
# Mail über SMTP an Provider Gateway
# Zuerst der Name des Gateways
SMTP_GATEWAY=smtp.server.provider.beispiel
ipchains -A output -i $EXTERNAL_INTERFACE -p tcp\
-s $IPADDR $UNPRIVPORTS \
-d $SMTP_GATEWAY 25 -j ACCEPT
ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y\
-s $SMTP_GATEWAY 25 \
-d $IPADDR $UNPRIVPORTS -j ACCEPT
Wenn aber stattdessen erwünscht ist, daß die Bastion selbst Mailserver ist,
also die Mail direkt zu verschicken, dann muß einfach statt der Angabe des
SMTP-Gateways ein $ANYWHERE verwendet werden:
# Mail über SMTP an Provider Gateway
ipchains -A output -i $EXTERNAL_INTERFACE -p tcp\
-s $IPADDR $UNPRIVPORTS \
-d $ANYWHERE 25 -j ACCEPT
ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y\
-s $ANYWHERE 25 \
-d $IPADDR $UNPRIVPORTS -j ACCEPT
Damit die Bastion aber auch ankommende Aufträge aus der DMZ akzeptieren
kann, bedarf es noch eines weiteren Regelsatzes für das Bastion-Script:
# Bastion nimmt SMTP Anfragen aus der DMZ entgegen
ipchains -A input -i $BASTION_DMZ_INTERFACE -p tcp \
-s $DMZ_ADDRESSES $UNPRIVPORTS \
-d $BASTION_DMZ_IPADDR 25 -j ACCEPT
ipchains -A output -i $BASTION_DMZ_INTERFACE -p tcp ! -y \
-s $BASTION_DMZ_IPADDR 25 \
-d $DMZ_ADDRESSES $UNPRIVPORTS -j ACCEPT
Jetzt müssen wir aber noch der Choke erlauben, SMTP-Pakete an die Bastion
durchzulassen. In das Choke Script muß folglich eingetragen werden:
# Choke erlaubt SMTP-Pakete an die Bastion
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p tcp\
-s CHOKE_DMZ_IPADDR $UNPRIVPORTS \
-d $BASTION_DMZ_IPADDR 25 -j ACCEPT
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p tcp ! -y\
-s $BASTION_DMZ_IPADDR 25 \
-d CHOKE_DMZ_IPADDR $UNPRIVPORTS -j ACCEPT
Damit sollte der Versand von E-Mail auch für die Rechner im LAN möglich
sein.
Die Rechner des LAN holen ihre Mails direkt bei der Bastion ab. Das
geschieht mit dem POP3 Protokoll (TCP 110). Die Bastion muß nur Pakete aus
der DMZ durchlassen, aus dem Internet ist dieser Service nicht verfügbar.
Das Bastion-Script bekommt also noch die Regeln:
# POP-Server der Bastion nimmt Pakete aus der DMZ entgegen
ipchains -A input -i $BASTION_DMZ_INTERFACE -p tcp \
-s $CHOKE_DMZ_IPADDR $UNPRIVPORTS \
-d $BASTION_DMZ_IPADDR 110 -j ACCEPT
ipchains -A output -i $BASTION_DMZ_INTERFACE -p tcp ! -y \
-s $BASTION_DMZ_IPADDR 110 \
-d $CHOKE_DMZ_IPADDR $UNPRIVPORTS -j ACCEPT
Natürlich muß jetzt auch wieder die Choke noch soweit konfiguriert werden,
daß sie Pakete durchlässt, die an die Bastion gerichtet sind. Das
Choke-Script wird um die folgenden Regeln erweitert:
# POP3 Pakete an die Bastion werden weitergegeben:
ipchains -A output -i $CHOKE_DMZ_INTERFACE -p tcp \
-s $CHOKE_DMZ_IPADDR $UNPRIVPORTS \
-d $BASTION_DMZ_IPADDR 110 -j ACCEPT
ipchains -A input -i $CHOKE_DMZ_INTERFACE -p tcp ! -y \
-s $BASTION_DMZ_IPADDR 110 \
-d $CHOKE_DMZ_IPADDR $UNPRIVPORTS -j ACCEPT
Damit wir hier jetzt nicht jeden denkbaren Internet-Dienst in epischer Breite
darstellen müssen, hier noch ein paar allgemeingültige Tips zum Aufbau der
einzelnen Regeln.
Der grundsätzliche Aufbau der Regeln ist immer gleich, die Bastion erlaubt
bestimmte Pakete, die Choke erlaubt die selben Pakete. Aber während die
Bastion die Pakete auf ihre interne Schnittstelle erlaubt, tut die Choke es
auf die externe. Man könnte fast von einer Art Achsensymetrie sprechen, die
Achse wäre in dem Fall die DMZ.
Um die richtigen Regeln für einen bestimmten Dienst zu erstellen, ist es
notwendig, ein Protokoll hinlänglich zu verstehen. Dazu können die im Anhang
aufgeführten Protokollbeschreibungen dienen. Diese Beschreibungen sind
selbstverständlich nicht vollständig, das würde den Rahmen der Darstellung
sprengen. Genauere Details können in den jeweiligen HOWTOS, den RFCs und
anderen Informationsquellen entnommen werden. Trotzdem sollte nach der
Durcharbeitung der letzten Abschnitte genügend Verständnis für eigene
Weiterentwicklungen vorhanden sein.
Bei allen Regeln, die wir in den letzten Abschnitten aufgestellt haben,
haben wir eine Kleinigkeit einfach weggelassen. Wir haben zwar der Choke
jeweils Regeln gegeben, die bestimmten Paketen erlauben, an die Bastion
weitergeleitet zu werden, wir haben aber der Choke niemals eine Regel
gegeben, die überhaupt Pakete aus dem LAN entgegennehmen würde.
In der Regel stellt es kein Sicherheitsproblem dar, wenn die Choke alle
Pakete aus dem zu schützenden Netz (LAN) akzeptiert, damit sparen wir uns
eine Menge zusätzlicher Regeln, wenn wir das pauschal für die Choke
formulieren:
# Vollständige Öffnung der Kommunikation zwischen LAN und Choke
ipchains -A input -i $CHOKE_LAN_INTERFACE \
-s $LAN_ADDRESSES -j ACCEPT
ipchains -A output -i $CHOKE_LAN_INTERFACE \
-d $LAN_ADDRESSES -j ACCEPT
Bis zu diesem Punkt der Darstellung haben weder die Bastion, noch die Choke
tatsächlich Pakete maskiert, aus diesem Grund hätte auch ein Datenverkehr
mit dem Internet bis jetzt noch nicht funktionieren können. In unserer DMZ
und im LAN arbeiten wir ja mit reservierten Adressen. (Auch wenn es in der
Praxus wenig Sinn macht, die DMZ wäre ja so von außen nicht ansprechbar)
Der erste Schritt ist jetzt also der, daß wir die Bastion zum
Masquerading-Server erklären, der alle Pakete, die von der Choke kommen,
auf seine echte Internet-Adresse maskiert. Das gesammte Netz wird so zum
Internet komplett versteckt.
# Bastion maskiert alle Pakete der Choke
ipchains -A forward -i $EXTERNAL_INTERFACE \
-s $CHOKE_DMZ_IPADDRESS -j MASQ
Damit jetzt aber auch alle Pakete aus dem LAN unter der Adresse der Choke an
die Bastion gehen, müssen wir auch die Choke als Masquerading Server
konfigurieren, die jetzt alle Pakete aus dem LAN mit ihrer DMZ-Adresse
maskiert. Das bietet auch eine doppelte Sicherheit, denn innerhalb der DMZ
ist damit das LAN unsichtbar, es existiert nur noch die Choke:
# Choke maskiert alle Pakete des LAN
ipchains -A forward -i $CHOKE_DMZ_INTERFACE \
-s $LAN_ADDRESSES -j MASQ
Nächste Seite: Wichtige Portnummern
Aufwärts: Crashkurs Firewallaufbau unter Linux
Vorherige Seite: Die Firewall als Router
  Inhalt
root
2001-08-07