next up previous contents
Nächste Seite: Wichtige Portnummern Aufwärts: Crashkurs Firewallaufbau unter Linux Vorherige Seite: Die Firewall als Router   Inhalt

Unterabschnitte

Exemplarischer Aufbau einer DMZ-Firewall

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.


\includegraphics{dmz2.eps}


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.

Die symbolischen Konstanten

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:

Die Konstanten für die Bastion

  # 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

Die Konstanten für die Choke

  #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

Weitere Grundeinstellungen

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.

ICMP-Nachrichten filtern

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.


Source-Quench Nachrichten

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.

Die Befehle für die Bastion

  # 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

Die Befehle für die Choke

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

Parameter-Problem Nachrichten

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.

Die Befehle für die Bastion

  # 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

Die Befehle für die Choke

  # 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

Destination-Unreachable Nachrichten

Dieser Nachrichtenpakettyp (Typ 3) ist eine allgemeine Fehlermeldung. Auch diese Nachrichten lassen wir für die Kommunikation mit der DMZ grundsätzlich durch.

Die Befehle für die Bastion

  # 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

Die Befehle für die Choke

  # 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

Time-Exceeded Nachrichten

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.

Die Befehle für die Bastion

  # 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 Befehle für die Choke

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

Ping Konfiguration

Der Befehl ping verwendet zwei unterschiedliche Nachrichtentypen, jeweils für Anfragen (echo-request - Typ 8) und Antworten (echo-reply - Typ 0).

ping Konfiguration der Bastion

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

ping Konfiguration der Choke

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

Dienste auf unprivilegierten Ports

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.

Domain Name Service

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.

Nutzung eines öffentlichen Nameservers

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.

Betreiben eigener Nameserver

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.

Konfiguration der Bastion als öffentlicher Nameserver

  # 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

Konfiguration der Choke als privater Nameserver

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

Der ident-Service (auth)

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.

Konfiguration der Bastion

  
    # 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

Konfiguration der Choke

  # 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

E-Mail

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.

Abgehende Mails über die Bastion verschicken

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.

Mailempfang über POP-Server auf der Bastion

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

Alle weiteren Dienste

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.

LAN Zugriff auf die Choke

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

Und schließlich das Masquerading

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


next up previous contents
Nächste Seite: Wichtige Portnummern Aufwärts: Crashkurs Firewallaufbau unter Linux Vorherige Seite: Die Firewall als Router   Inhalt
root 2001-08-07