[OpenBSD]

[Zurück: Authpf: Benutzer-Shell für authentifizierende Gateways] [Inhalt] [Weiter: Firewall für zuhause oder ein kleines Büro]

PF: Firewallredundanz mit CARP und pfsync


Inhaltsverzeichnis


Einführung in CARP

CARP ist das »Common Address Redundancy«-Protokoll. Sein Hauptzweck ist es, mehreren Hosts in einem gleichen Netzwerksegment zu ermöglichen, eine IP-Adresse zu teilen. CARP ist eine sichere und freie Alternative zum »Virtual Router Redundancy«-Protokoll (VRRP) und zum »Hot Standby Router«-Protokoll (HSRP).

CARP funktioniert, indem es einer Gruppe mehreren Hosts in einem gleichen Netzwerksegment ermöglicht, sich eine IP-Adresse zu teilen. Eine solche Gruppe wird als Redundanzgruppe bezeichnet (im Folgenden nur Gruppe genannt). Dieser Gruppe ist eine IP-Adresse zugeteilt, die sich die Gruppenmitglieder untereinander teilen. Innerhalb der Gruppe arbeitet ein Host als Master, die restlichen Hosts in der Gruppe als Backup. Der Masterhost hält die zugewiesene IP-Adresse; er reagiert auf den gesamten Netzwerkverkehr und auf ARP-Anfragen, die an ihn bzw. an die ihm zugewiesene IP gerichtet sind. Jeder Host kann einer oder mehreren Gruppen zugeteilt sein.

In der Praxis wird CARP häufig dazu genutzt, eine Gruppe von redundanten Firewalls zu erstellen. Die virtuelle IP, die der Gruppe zugeteilt ist, wird bei den Netzwerkclients als das standardmäßige Gateway konfiguriert. Sollte nun der Masterhost der Gruppe ausfallen, so wird einer der Backuphosts in der Gruppe seine Funktion übernehmen.

CARP unterstützt IPv4 und IPv6.

Funktionsweise von CARP

Der Masterhost sendet in regelmäßigen Zeitintervallen Nachrichten an das lokale Netzwerk, um den Backuphosts mitzuteilen, dass er im Betrieb ist. Wenn die Backuphosts nach einer festgelegten Zeitspanne keine dieser Nachrichten registrieren, wird einer der Backuphosts an dessen Stelle treten und dessen Dienst übernehmen. Der Backuphost, der die niedrigsten Werten für advbase und advskew hat, wird die Aufgabe übernehmen.

Es ist möglich, mehrere CARP-Gruppen in einem gleichen Netzwerksegment einzurichten. Die CARP-Nachrichten beinhalten eine »Virtual Host ID«, welche es den Hosts ermöglicht, zwischen den verschiedenen Gruppen zu unterscheiden.

Um eine Gruppe vor gefälschten CARP-Nachrichten zu schützen, ist es möglich, jede dieser Gruppen mit Passwortschutz zu versehen. Jedes gesendete Paket ist durch einen SHA1-HMAC geschützt.

CARP ist ein eigenständiges Protokoll, sodass extra definierte pass-Regeln im Regelsatz verwendet werden sollten.

pass out on $carp_dev proto carp keep state

$carp_dev sollte das physikalische Interface sein, über welches CARP kommuniziert.

Konfiguration von CARP

Jede Gruppe wird durch ein virtuelles carp(4)-Netzwerkinterface dargestellt. Als solches wird es auch mit ifconfig(8) konfiguriert.
ifconfig carpN create

ifconfig carpN vhid vhid [pass password] [carpdev carpdev] \
   [advbase advbase] [advskew advskew] [state state] ipaddress \
   netmask mask
carpN
Der Name des virtuellen carp(4)-Interfaces, wobei N die Interface-Nummer ist (z. B. carp10).
vhid
Die »Virtual Host ID«. Dies ist eine Nummer, die eine Gruppe innerhalb eines Netzwerksegments eindeutig identifiziert. Gültige Werte sind 1 bis 255.
password
Das Passwort, welches die Mitglieder einer Gruppe nutzen, um sich untereinander zu authentifizieren. Alle Hosts in einer Gruppe müssen das gleiche Passwort benutzen.
carpdev
Dieser Parameter ist optional. Er gibt das physikalische Interface an, welches dem Netzwerksegment zugeordnet ist, in dem sich die Gruppe befindet. Standardmäßig versucht CARP, das richtige Interface selbst zu finden. Dabei sucht es anhand der Kombination aus Netzwerkmaske (mask) und IP-Adresse (ipaddress) nach dem Interface, das in dem gleichen Subnetz ist wie das carp(4)-Interface.
advbase
Dieser Parameter ist optional. Er gibt an, in welchen Zeitintervallen der Host Nachrichten an die Gruppe senden soll, die signalisieren, dass der Host ein Mitglied der Gruppe ist. Gültige Werte sind 1 bis 255. Der Standardwert ist 1.
advskew
Dieser optionale Parameter gibt an, wie sehr advbase gestreckt werden soll, wenn CARP-Advertisements gesendet werden. Durch die Einstellung von advskew kann der Master-CARP-Host festgelegt werden. Je höher der Wert ist, desto geringer ist seine Berechtigung, die Rolle vom Masterhost einzunehmen. Gültige Werte sind 0 bis 254. Der Standardwert ist 0.
state
Zwingt das carp(4)-Interface dazu, einen bestimmten Status anzunehmen. Gültige Werte sind init, backup und master.
ipaddress
Dies ist die IP-Adresse, die der Gruppe zugewiesen wird. Diese Adresse darf nicht im selben Subnetz sein wie die IP-Adresse, die dem physikalischen Interface zugeordnet ist (sofern vorhanden). Die Adresse muss jedem Host in der Gruppe zugewiesen sein.
mask
Die Subnetzmaske der gemeinsam genutzten IP.

Weiterhin kann das Verhalten von CARP via sysctl(8) manipuliert werden.

net.inet.carp.allow
Akzeptiert eingehende CARP-Pakete - oder nicht. Standardwert ist 1 (akzeptiert).
net.inet.carp.preempt
Erlaubt Hosts innerhalb einer Gruppe, die einen besseren advbase- und advskew-Wert haben, zum Masterhost zu werden. Zusätzlich erlaubt diese Option das Herunterfahren aller Interfaces in dem Fall, dass ein Interface ausfällt. Wenn ein physikalisches CARP-Interface herunterfährt, wird CARP advskew bei allen anderen CARP-Schnittstellen auf den Wert 240 setzen. Im Wesentlichen wird er sich so selbst von seinem Dienst suspendieren. Standardwert ist 0 (aus).
net.inet.carp.log
Zeichnet fehlerhafte CARP-Pakete auf. Standard ist 0 (aus).
net.inet.carp.arpbalance
Ermöglicht Lastverteilung zwischen mehreren Gruppen. Standard ist 0 (aus). Siehe auch carp(4) für weitere Informationen.

CARP-Beispiel

Es folgt eine Beispielkonfiguration für CARP.
# sysctl -w net.inet.carp.allow=1
# ifconfig carp1 create
# ifconfig carp1 vhid 1 pass mekmitasdigoat carpdev em0 \
    advskew 100 10.0.0.1 netmask 255.255.255.0

Das bewirkt Folgendes:

Ein Aufruf von ifconfig für carp1 zeigt den Status des Interfaces an.

# ifconfig carp1
carp1: flags=8802<UP,BROADCAST,SIMPLEX,MULTICAST> mtu 1500
     carp: BACKUP carpdev em0 vhid 1 advbase 1 advskew 100
     groups: carp
     inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255

Einführung in pfsync

Das pfsync(4)-Netzwerkinterface zeigt bestimmte Änderungen des pf(4)-Zustands (seiner Tabellen) an. Durch die Nutzung von tcpdump(8) können diese Änderungen in Echtzeit überwacht werden. Zusätzlich kann das pfsync(4)-Interface diese Änderungen an andere Hosts im Netzwerk senden, sodass diese den Zustand ihrer Tabellen entsprechend angleichen können. Ebenso kann pfsync(4) auf solche Nachrichten aus dem Netzwerk warten und diese lesen.

Funktionsweise von pfsync

Standardmäßig sendet oder empfängt pfsync(4) keine derartigen Meldungen über das Netzwerk. Dennoch können die Updates mittels tcpdump(8) oder anderen Programmen mitverfolgt werden.

Wenn pfsync(4) so konfiguriert ist, diese Nachrichten über das Netzwerk zu senden und zu empfangen, werden die Nachrichten an alle Teilnehmer der Gruppe versendet. All diese Updateinformationen werden jedoch ohne Authentifizierung versendet. Um hier für Sicherheit zu sorgen, gibt es zwei bewährte Verfahren:

  1. Verbinde die zwei Maschinen, die ihre Updates untereinander austauschen sollen, mit einem Crossover-Kabel und konfiguriere das Interface als syncdev (siehe hier).
  2. Benutze die ifconfig(8)-Option syncpeer (siehe unten), um eine Unicastverbindung über das Netzwerk zwischen den Maschinen aufzubauen, über die sie die Nachrichten austauschen können. Danach konfiguriere ipsec(4), um die Verbindung abzusichern.

Wenn die Updates über das Netzwerk gesendet und empfangen werden, sollten diese pfsync-Pakete auch im Regelsatz so berücksichtigt werden, dass sie auch ihr Ziel erreichen können.

pass on $sync_if proto pfsync

$sync_if sollte das physikalische Interface sein, über das pfsync(4) kommuniziert.

Konfiguration von pfsync

Da pfsync(4) als virtuelles Netzwerkinterface arbeitet, wird es mit ifconfig(8) konfiguriert.
ifconfig pfsyncN syncdev syncdev [syncpeer syncpeer]
pfsyncN
Der Name des pfsync(4)-Interfaces. pfsync0 ist standardmäßig benutzbar, wenn der generische Kernel (GENERIC) verwendet wird.
syncdev
Der Name des physikalischen Interfaces, worüber pfsync die Updates versendet.
syncpeer
Dieser Parameter ist optional. Er gibt den Host an, an den Updates als Unicastnachrichten versendet werden sollen. Standardmäßig werden die Updatenachrichten als Multicastnachricht an die Gruppe im lokalen Netzwerk gesendet. Diese Option überschreibt das Verhalten und sendet stattdessen das Update per Unicastnachricht an den angegebenen syncpeer.

pfsync-Beispiel

Es folgt eine pfsync-Beispielkonfiguration.
# ifconfig pfsync0 syncdev em1
Dies aktiviert pfsync auf dem em1-Interface. Ausgehender Verkehr wird via Multicast in das Netzwerk gesendet. Jeder Host mit aktiviertem pfsync kann die Updates empfangen.

Kombinieren von CARP und pfsync für Ausfallsicherheit und Redundanz

Durch die Kombination der Fähigkeiten von CARP und pfsync lässt sich eine Gruppe von zwei oder mehr Hosts zu einem Firewallcluster mit hoher Verfügbarkeit und Redundanz erstellen.
CARP:
Regelt automatisch die Ausfallsicherheit, indem ein anderer Host seine Aufgabe bei einem Ausfall übernimmt.
pfsync:
Synchronisiert die Statustabellen zwischen allen Firewalls in einer Gruppe. Wenn eine Firewall ausfallen sollte, kann der Netzwerkverkehr ohne Unterbrechung über den neuen Firewallhost laufen. Der neue Firewallhost hat stets eine aktuelle Statustabelle und kann sofort seine Arbeit verrichten.

Ein Beispielszenario. Zwei Firewalls: fw1 und fw2. +------| WAN/Internet |------+ | | em2| |em2 +-----+ +-----+ | fw1 |-em1--------------em1-| fw2 | +-----+ +-----+ em0| |em0 | | ---+--gemeinsam genutztes LAN---+---

Die Firewalls sind über ein Crossover-Kabel miteinander über em1 verbunden. Beide sind an das LAN mit em0 und an das WAN (bzw. Internet) an em2 angeschlossen. Die IP-Adressen wurden folgendermaßen vergeben:

Als Firewall-Masterhost wird fw1 festgelegt.

Konfiguration von fw1:

! aktiviere Preemptivität und Ausfallsicherheit für Gruppeninterfaces # sysctl -w net.inet.carp.preempt=1 ! pfsync konfigurieren # ifconfig em1 10.10.10.1 netmask 255.255.255.0 # ifconfig pfsync0 syncdev em1 # ifconfig pfsync0 up ! CARP auf dem LAN-Interface konfigurieren # ifconfig carp1 create # ifconfig carp1 vhid 1 carpdev em0 pass lanpasswd \ 172.16.0.100 netmask 255.255.255.0 ! CARP auf dem WAN/Internet-Interface konfigurieren. # ifconfig carp2 create # ifconfig carp2 vhid 2 carpdev em2 pass netpasswd \ 192.0.2.100 netmask 255.255.255.0

Konfiguration von fw2:

! aktiviere Preemptivität und Ausfallsicherheit für Gruppeninterfaces # sysctl -w net.inet.carp.preempt=1 ! pfsync konfigurieren # ifconfig em1 10.10.10.2 netmask 255.255.255.0 # ifconfig pfsync0 syncdev em1 # ifconfig pfsync0 up ! CARP auf dem LAN-Interface konfigurieren # ifconfig carp1 create # ifconfig carp1 vhid 1 carpdev em0 pass lanpasswd \ advskew 128 172.16.0.100 netmask 255.255.255.0 ! CARP auf dem WAN/Internet-Interface konfigurieren. # ifconfig carp2 create # ifconfig carp2 vhid 2 carpdev em2 pass netpasswd \ advskew 128 192.0.2.100 netmask 255.255.255.0

Weitere technische Möglichkeiten

Weitere technische Möglichkeiten im Umgang mit CARP und pfsync.

CARP und pfsync während des Bootvorgangs konfigurieren

Da carp(4) und pfsync besondere Netzwerkinterfacetypen sind, lassen sie sich während des Bootvorgangs konfigurieren, indem man für sie eine hostname.if(5)-Datei anlegt. Das Skript netstart wird während des Bootens dann anhand diesen Dateien die Konfiguration durchführen.

Beispiele:

/etc/hostname.carp1
inet 172.16.0.100 255.255.255.0 172.16.0.255 vhid 1 carpdev em0 \
    pass lanpasswd

/etc/hostname.pfsync0
up syncdev em1

Ausfallsicherheit vom Master-Host testen

Es kann irgendwann die Zeit kommen, in der der Masterhost ausfällt, bzw. sein Dienst vorübergehend eingestellt werden muss. Dies kann geschehen, wenn man den Masterhost warten muss oder ein Problem besteht, welches zu beheben ist. Das Ziel ist es, den Masterhost von seinem Dienst zu suspendieren, ohne dass der Netzwerkverkehr davon beeinträchtigt wird. Dazu muss einer der Backuphosts den Dienst des Masterhosts übernehmen.

Um einen solchen Ausfall für eine bestimmte CARP-Gruppe zu erzwingen, fahre das carp(4)-Interface auf dem Masterhost herunter. Das führt dazu, dass der Masterhost sich selber mit »unendlich hohen« advbase und advskew ankündigen wird. Der Backuphost (oder einer davon) wird das merken und ab sofort die Rolle vom Masterhost übernehmen.

# ifconfig carp1 down

Eine Alternative wäre advskew zu vergrößern, sodass der Wert größer ist als advskew auf dem Backuphost (bzw. den anderen Backuphosts). Damit wird ein Failover hervorgerufen, der es dem Master ermöglicht, weiterhin in der CARP-Gruppe verfügbar zu sein.

Eine andere Möglichkeit, um Ausfallsicherheit zu gewährleisten, ist die Anpassung des CARP-Demotionzählers. Der Demtionzähler gilt als Maß dafür, wie »bereit« ein Host ist, der Master der CARP-Gruppe zu werden. Wenn ein Host zum Beispiel gerade dabei ist hochzufahren, wäre es eine schlechte Idee, ihn als CARP-Master zu deklarieren, bis alle Interfaces eingerichtet, alle Netzwerkdaemons gestartet wurden etc. Hosts, die einen hohen Demotionwert versenden, werden seltener als Master ausgewählt.

Ein Demotionzähler wird in jeder Interfacegruppe gespeichert, zu der das CARP-Interface gehört. Standardmäßig sind alle CARP-Interfaces Mitglied der »carp«-Interfacegruppe. Der aktuelle Wert des Demotioncounters kann mit ifconfig(8) angezeigt werden:

# ifconfig -g carp
carp: carp demote count 0

In diesem Beispiel wird der Zähler der »carp«-Interfacegruppe angezeigt. Wenn ein CARP-Host sich selbst im Netzwerk anbietet, so wird die Summe aller Demotionzähler der Interfacegruppen versendet, zu denen das carp(4)-Interface gehört. Das heißt, dass der versendete Demotionwert die Summe aller Zähler darstellt.

Nehmen wir nun folgendes Beispiel an. Zwei Firewalls mit CARP besitzen folgende CARP-Interfaces:

Das Ziel besteht darin, nur die carp1- und carp2-Gruppen im Falle eines Ausfalls auf die zweite Firewall umzuleiten.

Zuerst müssen beide zuerst zu einer neuen Interfacegruppe hinzugefügt werden. In diesem Beispiel nennen wir sie »internal«:

# ifconfig carp1 group internal
# ifconfig carp2 group internal
# ifconfig internal
carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
     carp: MASTER carpdev em0 vhid 1 advbase 1 advskew 100
     groups: carp internal
     inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255
carp2: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
     carp: MASTER carpdev em1 vhid 2 advbase 1 advskew 100
     groups: carp internal
     inet 10.0.1.1 netmask 0xffffff00 broadcast 10.0.1.255

Nun erhöhen wir den Demotionzähler für die Gruppe »internal« mittels ifconfig(8):

# ifconfig -g internal
internal: carp demote count 0
# ifconfig -g internal carpdemote 50
# ifconfig -g internal
internal: carp demote count 50

Die Firewall wird nun im Falle eines Ausfalls die Gruppen carp1 und carp2 gerne an die andere Firewall im Cluster übergeben, doch weiterhin Master von carp3 und carp4 bleiben. Wenn die andere Firewall nun selbst beginnt, sich mit einem Demotionwert über 50 anzubieten, oder die andere Firewall aufhört, ihren Wert zu übermitteln, so wird diese Firewall wie zuvor die Gruppen carp1 und carp2 übernehmen.

Um auf die primäre Firewall zurückfallen zu können, mach die Änderungen wieder rückgängig:

# ifconfig -g internal -carpdemote 50
# ifconfig -g internal
internal: carp demote count 0

Netzwerkdaemons wie zum Beispiel OpenBGPD und sasyncd(8) verwenden den Demotioncounter, um sicherzustellen, dass die Firewall nicht zum Master wird, bevor die BGP-Sitzung aufgebaut und IPsec-SAs synchronisiert wurden.

Tipps für Regelsätze

Filter das physikalische Interface. Soweit es PF anbelangt, wird der Netzwerkverkehr vom physikalischen Interface und nicht vom virtuellen CARP-Interface (d. h. carp0) empfangen. Schreibe also deine Regelsätze dementsprechend. Vergiss nicht, dass ein Interfacename in einer PF-Regel entweder der Name eines physikalischen Interfacess oder eine dem Interface zugewiesene Adresse sein kann. Zum Beispiel könnte diese Regel korrekt sein:
pass in on fxp0 inet proto tcp from any to carp0 port 22
Das Ersetzen von fxp0 in carp0 würde aber nicht das machen, was du erwartest.

Vergiss NIEMALS, proto carp und proto pfsync zu übergeben!

Weitere Referenzen

Bitte folge den Links für weitere Informationen zu dem Thema.

[Zurück: Authpf: Benutzer-Shell für authentifizierende Gateways] [Inhalt] [Weiter: Firewall für zuhause oder ein kleines Büro]


[zurück] www@openbsd.org
$OpenBSD: carp.html,v 1.18 2007/11/12 20:29:59 saad Exp $