OPNsense HA Umsetzung: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
(→Master) |
|||
| (18 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
| − | + | =Plan= | |
| − | + | {{#drawio:ha-opnsense-kit}} | |
| − | {{#drawio: | ||
| − | |||
| − | |||
| + | == Platzhalter in diesem Artikel == | ||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Platzhalter !! Bedeutung !! Beispiel |
| − | |||
| − | |||
|- | |- | ||
| − | | | + | | '''HS''' || Drittes Oktett des Schulungsnetzes (WAN), wird vom Trainer vorgegeben || 4 |
|- | |- | ||
| − | | | + | | '''X''' || Deine Teilnehmernummer, wird vom Trainer vorgegeben || 13 |
|} | |} | ||
| − | + | * Beispiel für X=13 und HS=4: WAN Master 192.168.4.53, WAN Backup 192.168.4.73, WAN-VIP 192.168.4.33, VHID 13 | |
| − | + | * '''Alle Passwörter in diesem Artikel sind Laborwerte und dürfen so niemals in eine produktive Umgebung übernommen werden.''' | |
| − | |||
| − | |||
| − | |||
| − | == | + | =Wichtig= |
| + | * Die Netzwerkkarten für LAN und WAN müssen '''im Hypervisor''' in den Promiscuous-Modus geschaltet werden – nicht in OPNsense. | ||
| + | ** VirtualBox: Maschine => Ändern => Netzwerk => Adapter => Erweitert => Promiscuous-Modus: '''Alle erlauben''' | ||
| + | ** Proxmox: Bridge ohne MAC-Filter bzw. entsprechende Bridge-Einstellung | ||
| + | * Das gilt sowohl für den Master als auch für das Backup. | ||
| − | + | ;Begründung | |
| − | + | * CARP verwendet virtuelle MAC-Adressen für die gemeinsame VIP. In virtualisierten Umgebungen werden Frames mit diesen MAC-Adressen vom Hypervisor standardmäßig verworfen, da sie nicht der echten VM-NIC zugeordnet sind. Ohne aktivierten Promiscuous-Modus erreichen CARP-Advertisements den Partner nicht, was zu Fehldetektion, unerwünschtem Failover und HA-Inkonsistenzen führt. | |
| − | |||
| − | * | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | == | + | = Vorbereitung = |
| + | * Zwei OPNsense-Installationen mit jeweils mind. 3 Netzwerkkarten | ||
| + | * Auf beiden Maschinen muss die '''gleiche OPNsense-Version''' laufen | ||
| + | * Die Anzahl der Netzwerkkarten muss auf beiden Maschinen gleich sein | ||
| + | * '''Die Reihenfolge und Anzahl der Netzwerkschnittstellen muss auf beiden Maschinen identisch sein!''' | ||
| + | * Empfehlung für beide Maschinen: | ||
| + | ** em0: LAN | ||
| + | ** em1: WAN | ||
| + | ** em2: SYN | ||
| + | * Am Anfang sollten so wenige Dienste wie möglich laufen | ||
| + | == opnsense-template klonen == | ||
| + | * Beim Klonen '''"Neue MAC-Adressen für alle Netzwerkkarten erzeugen"''' auswählen | ||
| − | === | + | == IP-Adressen der Backup Firewall == |
| + | ;Template klonen als opns-ha2 | ||
| + | ====System-Settings: General==== | ||
| + | *Hostname: opns-ha2 | ||
| + | *Theme: opnsense-dark | ||
| + | * Gateway anlegen: 192.168.HS.254 und später WAN zuordnen | ||
| + | * em0 (LAN): 192.168.1.2/24 | ||
| + | * em1 (WAN): 192.168.HS.X+60/24 | ||
| + | * em2 (SYN): 100.64.64.2/30 | ||
| − | + | == IP-Adressen der Master Firewall == | |
| + | ;Template klonen als opns-ha1 | ||
| + | ====System-Settings: General==== | ||
| + | *Hostname: opns-ha1 | ||
| + | *Theme: opnsense | ||
| + | * Gateway anlegen: 192.168.HS.254 und später WAN zuordnen | ||
| + | * em0 (LAN): 192.168.1.1/24 (bereits aus dem Template) | ||
| + | * em1 (WAN): 192.168.HS.X+40/24 | ||
| + | * em2 (SYN): 100.64.64.1/30 | ||
| + | == Übersicht == | ||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! !! Master (opns-ha1) !! Backup (opns-ha2) !! VIP !! VHID |
|- | |- | ||
| − | | | + | | LAN (em0) || 192.168.1.1 || 192.168.1.2 || 192.168.1.3 || 100 |
|- | |- | ||
| − | | | + | | WAN (em1) || 192.168.HS.X+40 || 192.168.HS.X+60 || 192.168.HS.X+20 || X |
|- | |- | ||
| − | | | + | | SYN (em2) || 100.64.64.1 || 100.64.64.2 || – || – |
| + | |} | ||
| + | |||
| + | * Die VHID muss nur innerhalb einer Broadcast-Domäne eindeutig sein, der Wertebereich ist 1 bis 255. | ||
| + | * Da sich alle Teilnehmer das WAN-Segment teilen, wird dort die Teilnehmernummer X verwendet (1 bis 13). | ||
| + | * Das LAN ist pro Teilnehmer ein eigenes, isoliertes Segment. Dort steht deshalb bei allen Teilnehmern fest die 100. Der Abstand zum WAN-Bereich ist Absicht: dreistellig = LAN, zweistellig = WAN. | ||
| + | |||
| + | = Firewall Regeln (beide Firewalls) = | ||
| + | * Auf dem '''WAN'''-Interface muss das Protokoll CARP akzeptiert werden | ||
| + | * Dazu im Menü '''Firewall => Rules => WAN''' eine Allow-Regel erstellen, die auf das CARP-Protokoll matcht | ||
| + | * Auf dem '''LAN'''-Interface genügt die Default-Regel "Default allow LAN to any" – sie erlaubt jedes Protokoll | ||
| + | ** Wird diese Regel später durch restriktive Regeln ersetzt, muss dort eine eigene CARP-Regel ergänzt werden, sonst bricht der Cluster im LAN auseinander | ||
| + | * Für das SYN-Interface eine Standard-Allow-Regel erstellen, die alles erlaubt | ||
| + | |||
| + | = Virtuelle IPs (Master Firewall) = | ||
| + | * Die virtuellen IPs werden von den Knoten des HA-Clusters geteilt, sobald ein Ausfall erkannt wird | ||
| + | * Somit wird dafür gesorgt, dass die virtuelle IP immer erreichbar ist | ||
| + | * Die virtuelle IP wird '''nur''' auf der Master Firewall eingestellt und an die Backups mitgeteilt | ||
| + | * Dazu muss man im Menü '''Interfaces => Virtual IPs => Settings''' an allen Schnittstellen bis auf das SYN-Interface die gewünschten IPs vergeben | ||
| + | * Über das '''[+]''' auf der rechten Seite muss man folgende Einträge machen: | ||
| + | |||
| + | == virtuelle WAN IP == | ||
| + | {| class="wikitable" | ||
| + | ! Parameter !! Wert | ||
| + | |- | ||
| + | | Mode || CARP | ||
|- | |- | ||
| − | | | + | | Interface || WAN |
|- | |- | ||
| − | | | + | | Address || 192.168.HS.X+20/24 |
|- | |- | ||
| − | | | + | | Virtual Password || radler |
|- | |- | ||
| − | | | + | | VHID Group || X |
|- | |- | ||
| − | | | + | | Advertising Frequency || 1 |
|- | |- | ||
| − | | | + | | Description || Virtual WAN IP |
|} | |} | ||
| − | + | == virtuelle LAN IP == | |
| − | |||
| − | |||
| − | === | ||
| − | |||
| − | |||
| − | |||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Parameter !! Wert |
|- | |- | ||
| − | | | + | | Mode || CARP |
|- | |- | ||
| − | | | + | | Interface || LAN |
|- | |- | ||
| − | | | + | | Address || 192.168.1.3/24 |
|- | |- | ||
| − | | | + | | Virtual Password || radler |
|- | |- | ||
| − | | | + | | VHID Group || 100 |
|- | |- | ||
| − | | | + | | Advertising Frequency || 1 |
|- | |- | ||
| − | | | + | | Description || Virtual LAN IP |
| + | |} | ||
| + | |||
| + | = Source NAT (Master Firewall) = | ||
| + | * Da die virtuelle IP für ausgehende Verbindungen benutzt werden soll, muss die automatische Regelgenerierung ausgeschaltet werden | ||
| + | * Im Menü '''Firewall => NAT => SNAT''' den Modus auf '''Manual''' stellen | ||
| + | * Dann die folgende Regel erstellen: | ||
| + | {| class="wikitable" | ||
| + | ! Parameter !! Wert | ||
| + | |- | ||
| + | | Interface || WAN | ||
|- | |- | ||
| − | | | + | | Source || LAN network |
|- | |- | ||
| − | | | + | | Translate Source IP || Virtual WAN IP (192.168.HS.X+20) |
|} | |} | ||
| − | = | + | = High Availability Konfiguration (Master Firewall) = |
| − | + | * Die eigentliche HA-Einstellung erfolgt über das Menü '''System => High Availability => Settings''': | |
| − | ''System | ||
| − | |||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Parameter !! Wert |
|- | |- | ||
| − | | | + | | Synchronize all states via || SYN |
|- | |- | ||
| − | | | + | | Sync compatibility || OPNsense 24.7 or above |
|- | |- | ||
| − | | | + | | Synchronize Peer IP || 100.64.64.2 |
|- | |- | ||
| − | | | + | | Synchronize Config || 100.64.64.2 |
|- | |- | ||
| − | | | + | | Verify peer || deaktiviert |
|- | |- | ||
| − | | | + | | Remote System Username || root |
|- | |- | ||
| − | | | + | | Remote System Password || radler |
|- | |- | ||
| − | | | + | | Services || Aliases, Firewall Rules, NAT, Virtual IPs |
| − | |||
| − | |||
|} | |} | ||
| − | + | * "Verify peer" bleibt deaktiviert, weil die Web-GUI der Gegenstelle ein selbstsigniertes Zertifikat verwendet. | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| + | = High Availability Konfiguration (Backup Firewall) = | ||
| + | * Hier darf im Menü '''System => High Availability => Settings''' nur folgendes eingestellt werden: | ||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Parameter !! Wert |
| + | |- | ||
| + | | Synchronize all states via || SYN | ||
|- | |- | ||
| − | | | + | | Sync compatibility || OPNsense 24.7 or above |
|- | |- | ||
| − | | | + | | Synchronize Peer IP || 100.64.64.1 |
|- | |- | ||
| − | | | + | | Synchronize Config || leer |
|- | |- | ||
| − | | | + | | Verify peer || deaktiviert |
| − | | | + | |- |
| − | + | | Remote System Username || leer | |
| − | |||
| − | |||
|- | |- | ||
| − | | | + | | Remote System Password || leer |
|- | |- | ||
| − | | | + | | Services || Nothing selected |
|} | |} | ||
| − | '' | + | * '''Synchronize Config''' muss auf dem Backup leer bleiben. Trägt man hier den Master ein, schieben sich beide Knoten gegenseitig ihre Konfiguration zu. |
| − | |||
| − | ''' | + | = Client im LAN = |
| − | + | * Der Windows-Client (192.168.1.50) muss als '''Gateway''' und als '''DNS-Server''' die LAN-VIP '''192.168.1.3''' erhalten – nicht die 192.168.1.1 | |
| − | + | * Wird die echte IP des Masters eingetragen, ist der Client beim Ausfall des Masters trotz funktionierendem Cluster offline | |
| − | + | * Bei Verwendung eines DHCP-Servers muss dieser die VIP als Gateway und DNS verteilen | |
| − | |||
| − | |||
| − | |||
| − | |||
| + | = Endergebnis = | ||
| + | ==Master== | ||
| + | * System | ||
| + | ** High Availability | ||
| + | *** Status | ||
| + | * Hier müssen beide Spalten gefüllt sein und auf beiden Knoten die gleichen Dienste erscheinen: | ||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Service !! Description |
| + | |- | ||
| + | | configd || Configd | ||
|- | |- | ||
| − | | | + | | cron || Cron |
|- | |- | ||
| − | | | + | | hostwatch || Hostwatch |
| − | | | + | |- |
| − | + | | login || Users and Groups | |
| − | + | |- | |
| − | + | | ntpd || Ntpd | |
| − | + | |- | |
| − | + | | openssh || Secure Shell | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
|- | |- | ||
| − | | | + | | pf || Packet Filter |
|- | |- | ||
| − | | | + | | routing || System routing |
|- | |- | ||
| − | | | + | | sysctl || System tunables |
|- | |- | ||
| − | | | + | | syslog-ng || Syslog-ng |
|- | |- | ||
| − | | | + | | unbound || Unbound DNS |
|- | |- | ||
| − | | | + | | webgui || Web GUI |
|} | |} | ||
| + | ;Wichtig: | ||
| + | '''Syncronize and reconfigure all''' | ||
| − | + | ==Slave== | |
| − | + | * System | |
| − | + | ** High Availability | |
| − | auf | + | *** Status |
| + | * Auf der Backup-Firewall erscheint hier die Warnung, dass die XMLRPC-Konfiguration unvollständig sei. | ||
| + | * Diese Meldung kann ignoriert werden: Das Backup empfängt nur passiv, deshalb sind die XMLRPC-Felder dort absichtlich leer und werden fälschlicherweise als "unvollständig" markiert. Solange die Master-Firewall auf Version 24.7 eingestellt ist und die Daten erfolgreich überträgt, arbeitet der Cluster technisch einwandfrei. | ||
| − | '' | + | = Failover testen = |
| − | + | * Auf dem Client einen Dauerping nach draußen starten: | |
| − | + | ping -t 192.168.HS.254 | |
| + | * Auf dem '''Master''': Interfaces => Virtual IPs => Status => '''Enter Persistent CARP Maintenance Mode''' | ||
| + | * Erwartetes Verhalten: | ||
| + | ** Das Backup wechselt für beide VHIDs von BACKUP auf MASTER | ||
| + | ** Der Ping läuft weiter oder verliert maximal ein bis zwei Pakete | ||
| + | * Kontrolle auf beiden Knoten: | ||
| + | ifconfig em0 ; ifconfig em1 | ||
| + | * Zurückschalten über '''Leave Persistent CARP Maintenance Mode''' auf dem Master | ||
| + | * Zweiter Test: Master hart ausschalten (VM stoppen) und das gleiche Verhalten prüfen | ||
| − | = | + | =Debugging= |
| − | + | == Vorgehen == | |
| + | * Von unten nach oben prüfen: erst CARP (Layer 2/3), dann pfsync (States), dann XMLRPC (Konfiguration) | ||
| + | * Ein Cluster kann sauber synchronisieren und trotzdem kein Failover können – und umgekehrt | ||
| + | == Schritt 1: CARP-Status == | ||
| + | * Auf beiden Knoten: | ||
| + | ifconfig em0 ; ifconfig em1 | ||
| + | * Erwartetes Bild: | ||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Knoten !! LAN (vhid 100) !! WAN (vhid X) |
|- | |- | ||
| − | | | + | | Master || MASTER, advskew 0 || MASTER, advskew 0 |
|- | |- | ||
| − | | | + | | Backup || BACKUP, advskew 100 || BACKUP, advskew 100 |
| − | |||
| − | |||
|} | |} | ||
| + | * In der GUI: '''Interfaces => Virtual IPs => Status''' | ||
| + | * CARP global ein-/ausgeschaltet: | ||
| + | sysctl net.inet.carp.allow | ||
| + | * Ausführlichere CARP-Meldungen im Log einschalten: | ||
| + | sysctl net.inet.carp.log=2 | ||
| − | + | == Schritt 2: Beide Knoten sind MASTER (Split Brain) == | |
| − | + | * Das häufigste Fehlerbild im Labor. Beide Knoten sehen den Partner nicht und übernehmen die VIP. | |
| + | * Prüfen, ob die Advertisements des Partners überhaupt ankommen: | ||
| + | tcpdump -n -i em1 proto 112 | ||
| + | tcpdump -n -i em0 proto 112 | ||
| + | * Man muss die Pakete '''beider''' Knoten sehen (Quelle = jeweils die echte Interface-IP) | ||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Beobachtung !! Ursache |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
|- | |- | ||
| − | | | + | | Nur eigene Pakete sichtbar || Promiscuous-Modus im Hypervisor fehlt |
|- | |- | ||
| − | | | + | | Gar keine Pakete sichtbar || VIP nicht angelegt oder Interface down |
|- | |- | ||
| − | | | + | | Pakete kommen an, trotzdem beide MASTER || CARP-Allow-Regel auf dem Interface fehlt |
|- | |- | ||
| − | | | + | | Pakete mit fremder VHID || Anderer Teilnehmer nutzt die gleiche VHID |
|} | |} | ||
| + | * Weitere Ursachen bei Split Brain: | ||
| + | ** Unterschiedliches '''Virtual Password''' auf den beiden Knoten | ||
| + | ** Unterschiedliche '''VHID''' auf den beiden Knoten | ||
| + | ** Unterschiedliche '''Advertising Frequency''' | ||
| − | + | == Schritt 3: Kein Failover trotz korrektem Status == | |
| − | + | * Demotion-Zähler prüfen – ist er größer als 0, bleibt der Knoten absichtlich BACKUP: | |
| − | + | sysctl net.inet.carp.demotion | |
| − | + | * Ursachen für einen erhöhten Zähler: ein Interface ist down, ein Dienst startet nicht sauber, der Knoten befindet sich noch im Maintenance Mode | |
| − | + | * Maintenance Mode verlassen: '''System => High Availability => Status => Leave persistent CARP maintenance mode''' | |
| − | + | == Schritt 4: Sicht des Clients == | |
| − | + | * Auf dem Windows-Client prüfen, welche MAC hinter dem Gateway steckt: | |
| + | arp -a | ||
| + | * Die LAN-VIP muss auf eine virtuelle MAC zeigen, nicht auf die echte NIC des Masters: | ||
| + | 192.168.1.3 00-00-5e-00-01-64 | ||
| + | * Das letzte Byte ist die VHID in hex – 0x64 = 100 | ||
| + | * Steht dort eine 08:00:27:... Adresse, arbeitet der Client an CARP vorbei direkt mit einer echten Firewall-IP | ||
| + | * Nach einem Failover darf sich der ARP-Eintrag '''nicht''' ändern – genau das ist der Sinn der virtuellen MAC | ||
| − | === | + | == Schritt 5: Zustandssynchronisation (pfsync) == |
| + | * Läuft der pfsync-Verkehr über das SYN-Netz? | ||
| + | tcpdump -n -i em2 proto 240 | ||
| + | * Anzahl der States auf beiden Knoten vergleichen – die Werte müssen ähnlich sein: | ||
| + | pfctl -s state | wc -l | ||
| + | * Ist die Zahl auf dem Backup dauerhaft 0, überträgt pfsync nicht: | ||
| + | ** '''Synchronize Peer IP''' zeigt auf die falsche Adresse | ||
| + | ** Die Allow-Regel auf dem SYN-Interface fehlt | ||
| + | ** SYN-Interface auf einem der Knoten nicht aktiviert | ||
| + | == Schritt 6: Konfigurationssynchronisation (XMLRPC) == | ||
| + | * Auf der Master-Firewall: '''System => Log Files => General''', im Filter-Feld '''xmlrpc''' eingeben | ||
| + | * Gesucht wird ein Eintrag wie: '''[OK] Configuration synchronized to''' https://100.64.64.2:443 | ||
| + | * Manuell anstoßen: '''System => High Availability => Status => Synchronize and reconfigure all (Push)''' | ||
| + | * Gleichzeitig auf dem Backup mitlesen: | ||
| + | tail -f /var/log/configd/latest.log | ||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Meldung !! Ursache |
| + | |- | ||
| + | | Connection refused || Web-GUI des Backups nicht erreichbar oder falscher Port | ||
|- | |- | ||
| − | | | + | | Authentication failed || Falsches Passwort unter "Remote System Password" |
|- | |- | ||
| − | | | + | | Certificate verify failed || "Verify peer" ist aktiviert, Zertifikat ist selbstsigniert |
|- | |- | ||
| − | | | + | | Endlose Sync-Schleife || Auf dem Backup ist "Synchronize Config" gefüllt – muss leer sein |
|} | |} | ||
| − | == | + | == Schritt 7: Ausgehende Verbindungen == |
| − | + | * Prüfen, mit welcher Quelladresse der Client nach draußen geht: | |
| − | + | tcpdump -n -i em1 host 192.168.HS.254 | |
| − | + | * Es muss die Virtual WAN IP (192.168.HS.X+20) erscheinen, nicht die echte IP des Masters | |
| − | + | * Erscheint die echte IP: Outbound-NAT steht noch auf automatisch, oder in der manuellen Regel wurde als Target nicht die VIP gewählt | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| + | == Nützliche Befehle im Überblick == | ||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Befehl !! Zweck |
| + | |- | ||
| + | | ifconfig em0 ; ifconfig em1 || CARP-Rolle und VIPs anzeigen | ||
| + | |- | ||
| + | | tcpdump -n -i em1 proto 112 || CARP-Advertisements mitlesen | ||
| + | |- | ||
| + | | tcpdump -n -i em2 proto 240 || pfsync-Verkehr mitlesen | ||
|- | |- | ||
| − | | | + | | pfctl -s state {{!}} wc -l || Anzahl der Firewall-States |
|- | |- | ||
| − | | | + | | sysctl net.inet.carp.demotion || Demotion-Zähler |
|- | |- | ||
| − | | | + | | sysctl net.inet.carp.log=2 || Ausführliches CARP-Logging |
|- | |- | ||
| − | | | + | | tail -f /var/log/configd/latest.log || Konfigurationssync mitlesen |
|- | |- | ||
| − | | | + | | configctl filter reload || Regelwerk neu laden |
|} | |} | ||
| − | ''' | + | ==Netzwerkschnittstellen== |
| + | === Master === | ||
| + | em0: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500 | ||
| + | description: LAN (lan) | ||
| + | options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG> | ||
| + | ether 08:00:27:c4:a2:6f | ||
| + | inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255 | ||
| + | '''inet 192.168.1.3 netmask 0xffffff00 broadcast 192.168.1.255 vhid 100''' | ||
| + | '''carp: MASTER vhid 100 advbase 1 advskew 0''' | ||
| + | '''peer 224.0.0.18 peer6 ff02::12''' | ||
| + | media: Ethernet autoselect (1000baseT <full-duplex>) | ||
| + | status: active | ||
| + | nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> | ||
| − | + | em1: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500 | |
| − | + | description: WAN (wan) | |
| − | + | options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG> | |
| + | ether 08:00:27:61:6f:6d | ||
| + | inet 192.168.HS.X+40 netmask 0xffffff00 broadcast 192.168.HS.255 | ||
| + | '''inet 192.168.HS.X+20 netmask 0xffffff00 broadcast 192.168.HS.255 vhid X''' | ||
| + | '''carp: MASTER vhid X advbase 1 advskew 0''' | ||
| + | '''peer 224.0.0.18 peer6 ff02::12''' | ||
| + | media: Ethernet autoselect (1000baseT <full-duplex>) | ||
| + | status: active | ||
| + | nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> | ||
| − | + | === Backup === | |
| − | + | em0: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500 | |
| + | description: LAN (lan) | ||
| + | options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG> | ||
| + | ether 08:00:27:1c:44:8b | ||
| + | inet 192.168.1.2 netmask 0xffffff00 broadcast 192.168.1.255 | ||
| + | '''inet 192.168.1.3 netmask 0xffffff00 broadcast 192.168.1.255 vhid 100''' | ||
| + | '''carp: BACKUP vhid 100 advbase 1 advskew 100''' | ||
| + | '''peer 224.0.0.18 peer6 ff02::12''' | ||
| + | media: Ethernet autoselect (1000baseT <full-duplex>) | ||
| + | status: active | ||
| + | nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> | ||
| − | + | em1: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500 | |
| + | description: WAN (wan) | ||
| + | options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG> | ||
| + | ether 08:00:27:95:9b:4b | ||
| + | inet 192.168.HS.X+60 netmask 0xffffff00 broadcast 192.168.HS.255 | ||
| + | '''inet 192.168.HS.X+20 netmask 0xffffff00 broadcast 192.168.HS.255 vhid X''' | ||
| + | '''carp: BACKUP vhid X advbase 1 advskew 100''' | ||
| + | '''peer 224.0.0.18 peer6 ff02::12''' | ||
| + | media: Ethernet autoselect (1000baseT <full-duplex>) | ||
| + | status: active | ||
| + | nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> | ||
| − | + | * Der Master hat '''advskew 0''', das Backup '''advskew 100'''. Diesen Wert setzt OPNsense beim Sync automatisch – er wird nicht von Hand vergeben. | |
| − | * | + | ==Wird Synchronisiert?== |
| + | ;Master | ||
| + | * System | ||
| + | ** High Availability | ||
| + | *** Status | ||
| + | **** Synchronize and reconfigure all (Push) | ||
| + | ;Backup | ||
| + | tail -f /var/log/configd/latest.log | ||
| + | * Hier sollte man die Übertragung sehen. | ||
Aktuelle Version vom 4. September 2026, 07:07 Uhr
Plan
Platzhalter in diesem Artikel
| Platzhalter | Bedeutung | Beispiel |
|---|---|---|
| HS | Drittes Oktett des Schulungsnetzes (WAN), wird vom Trainer vorgegeben | 4 |
| X | Deine Teilnehmernummer, wird vom Trainer vorgegeben | 13 |
- Beispiel für X=13 und HS=4: WAN Master 192.168.4.53, WAN Backup 192.168.4.73, WAN-VIP 192.168.4.33, VHID 13
- Alle Passwörter in diesem Artikel sind Laborwerte und dürfen so niemals in eine produktive Umgebung übernommen werden.
Wichtig
- Die Netzwerkkarten für LAN und WAN müssen im Hypervisor in den Promiscuous-Modus geschaltet werden – nicht in OPNsense.
- VirtualBox: Maschine => Ändern => Netzwerk => Adapter => Erweitert => Promiscuous-Modus: Alle erlauben
- Proxmox: Bridge ohne MAC-Filter bzw. entsprechende Bridge-Einstellung
- Das gilt sowohl für den Master als auch für das Backup.
- Begründung
- CARP verwendet virtuelle MAC-Adressen für die gemeinsame VIP. In virtualisierten Umgebungen werden Frames mit diesen MAC-Adressen vom Hypervisor standardmäßig verworfen, da sie nicht der echten VM-NIC zugeordnet sind. Ohne aktivierten Promiscuous-Modus erreichen CARP-Advertisements den Partner nicht, was zu Fehldetektion, unerwünschtem Failover und HA-Inkonsistenzen führt.
Vorbereitung
- Zwei OPNsense-Installationen mit jeweils mind. 3 Netzwerkkarten
- Auf beiden Maschinen muss die gleiche OPNsense-Version laufen
- Die Anzahl der Netzwerkkarten muss auf beiden Maschinen gleich sein
- Die Reihenfolge und Anzahl der Netzwerkschnittstellen muss auf beiden Maschinen identisch sein!
- Empfehlung für beide Maschinen:
- em0: LAN
- em1: WAN
- em2: SYN
- Am Anfang sollten so wenige Dienste wie möglich laufen
opnsense-template klonen
- Beim Klonen "Neue MAC-Adressen für alle Netzwerkkarten erzeugen" auswählen
IP-Adressen der Backup Firewall
- Template klonen als opns-ha2
System-Settings: General
- Hostname: opns-ha2
- Theme: opnsense-dark
- Gateway anlegen: 192.168.HS.254 und später WAN zuordnen
- em0 (LAN): 192.168.1.2/24
- em1 (WAN): 192.168.HS.X+60/24
- em2 (SYN): 100.64.64.2/30
IP-Adressen der Master Firewall
- Template klonen als opns-ha1
System-Settings: General
- Hostname: opns-ha1
- Theme: opnsense
- Gateway anlegen: 192.168.HS.254 und später WAN zuordnen
- em0 (LAN): 192.168.1.1/24 (bereits aus dem Template)
- em1 (WAN): 192.168.HS.X+40/24
- em2 (SYN): 100.64.64.1/30
Übersicht
| Master (opns-ha1) | Backup (opns-ha2) | VIP | VHID | |
|---|---|---|---|---|
| LAN (em0) | 192.168.1.1 | 192.168.1.2 | 192.168.1.3 | 100 |
| WAN (em1) | 192.168.HS.X+40 | 192.168.HS.X+60 | 192.168.HS.X+20 | X |
| SYN (em2) | 100.64.64.1 | 100.64.64.2 | – | – |
- Die VHID muss nur innerhalb einer Broadcast-Domäne eindeutig sein, der Wertebereich ist 1 bis 255.
- Da sich alle Teilnehmer das WAN-Segment teilen, wird dort die Teilnehmernummer X verwendet (1 bis 13).
- Das LAN ist pro Teilnehmer ein eigenes, isoliertes Segment. Dort steht deshalb bei allen Teilnehmern fest die 100. Der Abstand zum WAN-Bereich ist Absicht: dreistellig = LAN, zweistellig = WAN.
Firewall Regeln (beide Firewalls)
- Auf dem WAN-Interface muss das Protokoll CARP akzeptiert werden
- Dazu im Menü Firewall => Rules => WAN eine Allow-Regel erstellen, die auf das CARP-Protokoll matcht
- Auf dem LAN-Interface genügt die Default-Regel "Default allow LAN to any" – sie erlaubt jedes Protokoll
- Wird diese Regel später durch restriktive Regeln ersetzt, muss dort eine eigene CARP-Regel ergänzt werden, sonst bricht der Cluster im LAN auseinander
- Für das SYN-Interface eine Standard-Allow-Regel erstellen, die alles erlaubt
Virtuelle IPs (Master Firewall)
- Die virtuellen IPs werden von den Knoten des HA-Clusters geteilt, sobald ein Ausfall erkannt wird
- Somit wird dafür gesorgt, dass die virtuelle IP immer erreichbar ist
- Die virtuelle IP wird nur auf der Master Firewall eingestellt und an die Backups mitgeteilt
- Dazu muss man im Menü Interfaces => Virtual IPs => Settings an allen Schnittstellen bis auf das SYN-Interface die gewünschten IPs vergeben
- Über das [+] auf der rechten Seite muss man folgende Einträge machen:
virtuelle WAN IP
| Parameter | Wert |
|---|---|
| Mode | CARP |
| Interface | WAN |
| Address | 192.168.HS.X+20/24 |
| Virtual Password | radler |
| VHID Group | X |
| Advertising Frequency | 1 |
| Description | Virtual WAN IP |
virtuelle LAN IP
| Parameter | Wert |
|---|---|
| Mode | CARP |
| Interface | LAN |
| Address | 192.168.1.3/24 |
| Virtual Password | radler |
| VHID Group | 100 |
| Advertising Frequency | 1 |
| Description | Virtual LAN IP |
Source NAT (Master Firewall)
- Da die virtuelle IP für ausgehende Verbindungen benutzt werden soll, muss die automatische Regelgenerierung ausgeschaltet werden
- Im Menü Firewall => NAT => SNAT den Modus auf Manual stellen
- Dann die folgende Regel erstellen:
| Parameter | Wert |
|---|---|
| Interface | WAN |
| Source | LAN network |
| Translate Source IP | Virtual WAN IP (192.168.HS.X+20) |
High Availability Konfiguration (Master Firewall)
- Die eigentliche HA-Einstellung erfolgt über das Menü System => High Availability => Settings:
| Parameter | Wert |
|---|---|
| Synchronize all states via | SYN |
| Sync compatibility | OPNsense 24.7 or above |
| Synchronize Peer IP | 100.64.64.2 |
| Synchronize Config | 100.64.64.2 |
| Verify peer | deaktiviert |
| Remote System Username | root |
| Remote System Password | radler |
| Services | Aliases, Firewall Rules, NAT, Virtual IPs |
- "Verify peer" bleibt deaktiviert, weil die Web-GUI der Gegenstelle ein selbstsigniertes Zertifikat verwendet.
High Availability Konfiguration (Backup Firewall)
- Hier darf im Menü System => High Availability => Settings nur folgendes eingestellt werden:
| Parameter | Wert |
|---|---|
| Synchronize all states via | SYN |
| Sync compatibility | OPNsense 24.7 or above |
| Synchronize Peer IP | 100.64.64.1 |
| Synchronize Config | leer |
| Verify peer | deaktiviert |
| Remote System Username | leer |
| Remote System Password | leer |
| Services | Nothing selected |
- Synchronize Config muss auf dem Backup leer bleiben. Trägt man hier den Master ein, schieben sich beide Knoten gegenseitig ihre Konfiguration zu.
Client im LAN
- Der Windows-Client (192.168.1.50) muss als Gateway und als DNS-Server die LAN-VIP 192.168.1.3 erhalten – nicht die 192.168.1.1
- Wird die echte IP des Masters eingetragen, ist der Client beim Ausfall des Masters trotz funktionierendem Cluster offline
- Bei Verwendung eines DHCP-Servers muss dieser die VIP als Gateway und DNS verteilen
Endergebnis
Master
- System
- High Availability
- Status
- High Availability
- Hier müssen beide Spalten gefüllt sein und auf beiden Knoten die gleichen Dienste erscheinen:
| Service | Description |
|---|---|
| configd | Configd |
| cron | Cron |
| hostwatch | Hostwatch |
| login | Users and Groups |
| ntpd | Ntpd |
| openssh | Secure Shell |
| pf | Packet Filter |
| routing | System routing |
| sysctl | System tunables |
| syslog-ng | Syslog-ng |
| unbound | Unbound DNS |
| webgui | Web GUI |
- Wichtig
Syncronize and reconfigure all
Slave
- System
- High Availability
- Status
- High Availability
- Auf der Backup-Firewall erscheint hier die Warnung, dass die XMLRPC-Konfiguration unvollständig sei.
- Diese Meldung kann ignoriert werden: Das Backup empfängt nur passiv, deshalb sind die XMLRPC-Felder dort absichtlich leer und werden fälschlicherweise als "unvollständig" markiert. Solange die Master-Firewall auf Version 24.7 eingestellt ist und die Daten erfolgreich überträgt, arbeitet der Cluster technisch einwandfrei.
Failover testen
- Auf dem Client einen Dauerping nach draußen starten:
ping -t 192.168.HS.254
- Auf dem Master: Interfaces => Virtual IPs => Status => Enter Persistent CARP Maintenance Mode
- Erwartetes Verhalten:
- Das Backup wechselt für beide VHIDs von BACKUP auf MASTER
- Der Ping läuft weiter oder verliert maximal ein bis zwei Pakete
- Kontrolle auf beiden Knoten:
ifconfig em0 ; ifconfig em1
- Zurückschalten über Leave Persistent CARP Maintenance Mode auf dem Master
- Zweiter Test: Master hart ausschalten (VM stoppen) und das gleiche Verhalten prüfen
Debugging
Vorgehen
- Von unten nach oben prüfen: erst CARP (Layer 2/3), dann pfsync (States), dann XMLRPC (Konfiguration)
- Ein Cluster kann sauber synchronisieren und trotzdem kein Failover können – und umgekehrt
Schritt 1: CARP-Status
- Auf beiden Knoten:
ifconfig em0 ; ifconfig em1
- Erwartetes Bild:
| Knoten | LAN (vhid 100) | WAN (vhid X) |
|---|---|---|
| Master | MASTER, advskew 0 | MASTER, advskew 0 |
| Backup | BACKUP, advskew 100 | BACKUP, advskew 100 |
- In der GUI: Interfaces => Virtual IPs => Status
- CARP global ein-/ausgeschaltet:
sysctl net.inet.carp.allow
- Ausführlichere CARP-Meldungen im Log einschalten:
sysctl net.inet.carp.log=2
Schritt 2: Beide Knoten sind MASTER (Split Brain)
- Das häufigste Fehlerbild im Labor. Beide Knoten sehen den Partner nicht und übernehmen die VIP.
- Prüfen, ob die Advertisements des Partners überhaupt ankommen:
tcpdump -n -i em1 proto 112 tcpdump -n -i em0 proto 112
- Man muss die Pakete beider Knoten sehen (Quelle = jeweils die echte Interface-IP)
| Beobachtung | Ursache |
|---|---|
| Nur eigene Pakete sichtbar | Promiscuous-Modus im Hypervisor fehlt |
| Gar keine Pakete sichtbar | VIP nicht angelegt oder Interface down |
| Pakete kommen an, trotzdem beide MASTER | CARP-Allow-Regel auf dem Interface fehlt |
| Pakete mit fremder VHID | Anderer Teilnehmer nutzt die gleiche VHID |
- Weitere Ursachen bei Split Brain:
- Unterschiedliches Virtual Password auf den beiden Knoten
- Unterschiedliche VHID auf den beiden Knoten
- Unterschiedliche Advertising Frequency
Schritt 3: Kein Failover trotz korrektem Status
- Demotion-Zähler prüfen – ist er größer als 0, bleibt der Knoten absichtlich BACKUP:
sysctl net.inet.carp.demotion
- Ursachen für einen erhöhten Zähler: ein Interface ist down, ein Dienst startet nicht sauber, der Knoten befindet sich noch im Maintenance Mode
- Maintenance Mode verlassen: System => High Availability => Status => Leave persistent CARP maintenance mode
Schritt 4: Sicht des Clients
- Auf dem Windows-Client prüfen, welche MAC hinter dem Gateway steckt:
arp -a
- Die LAN-VIP muss auf eine virtuelle MAC zeigen, nicht auf die echte NIC des Masters:
192.168.1.3 00-00-5e-00-01-64
- Das letzte Byte ist die VHID in hex – 0x64 = 100
- Steht dort eine 08:00:27:... Adresse, arbeitet der Client an CARP vorbei direkt mit einer echten Firewall-IP
- Nach einem Failover darf sich der ARP-Eintrag nicht ändern – genau das ist der Sinn der virtuellen MAC
Schritt 5: Zustandssynchronisation (pfsync)
- Läuft der pfsync-Verkehr über das SYN-Netz?
tcpdump -n -i em2 proto 240
- Anzahl der States auf beiden Knoten vergleichen – die Werte müssen ähnlich sein:
pfctl -s state | wc -l
- Ist die Zahl auf dem Backup dauerhaft 0, überträgt pfsync nicht:
- Synchronize Peer IP zeigt auf die falsche Adresse
- Die Allow-Regel auf dem SYN-Interface fehlt
- SYN-Interface auf einem der Knoten nicht aktiviert
Schritt 6: Konfigurationssynchronisation (XMLRPC)
- Auf der Master-Firewall: System => Log Files => General, im Filter-Feld xmlrpc eingeben
- Gesucht wird ein Eintrag wie: [OK] Configuration synchronized to https://100.64.64.2:443
- Manuell anstoßen: System => High Availability => Status => Synchronize and reconfigure all (Push)
- Gleichzeitig auf dem Backup mitlesen:
tail -f /var/log/configd/latest.log
| Meldung | Ursache |
|---|---|
| Connection refused | Web-GUI des Backups nicht erreichbar oder falscher Port |
| Authentication failed | Falsches Passwort unter "Remote System Password" |
| Certificate verify failed | "Verify peer" ist aktiviert, Zertifikat ist selbstsigniert |
| Endlose Sync-Schleife | Auf dem Backup ist "Synchronize Config" gefüllt – muss leer sein |
Schritt 7: Ausgehende Verbindungen
- Prüfen, mit welcher Quelladresse der Client nach draußen geht:
tcpdump -n -i em1 host 192.168.HS.254
- Es muss die Virtual WAN IP (192.168.HS.X+20) erscheinen, nicht die echte IP des Masters
- Erscheint die echte IP: Outbound-NAT steht noch auf automatisch, oder in der manuellen Regel wurde als Target nicht die VIP gewählt
Nützliche Befehle im Überblick
| Befehl | Zweck |
|---|---|
| ifconfig em0 ; ifconfig em1 | CARP-Rolle und VIPs anzeigen |
| tcpdump -n -i em1 proto 112 | CARP-Advertisements mitlesen |
| tcpdump -n -i em2 proto 240 | pfsync-Verkehr mitlesen |
| wc -l | Anzahl der Firewall-States |
| sysctl net.inet.carp.demotion | Demotion-Zähler |
| sysctl net.inet.carp.log=2 | Ausführliches CARP-Logging |
| tail -f /var/log/configd/latest.log | Konfigurationssync mitlesen |
| configctl filter reload | Regelwerk neu laden |
Netzwerkschnittstellen
Master
em0: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500 description: LAN (lan) options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG> ether 08:00:27:c4:a2:6f inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255 inet 192.168.1.3 netmask 0xffffff00 broadcast 192.168.1.255 vhid 100 carp: MASTER vhid 100 advbase 1 advskew 0 peer 224.0.0.18 peer6 ff02::12 media: Ethernet autoselect (1000baseT <full-duplex>) status: active nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
em1: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500 description: WAN (wan) options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG> ether 08:00:27:61:6f:6d inet 192.168.HS.X+40 netmask 0xffffff00 broadcast 192.168.HS.255 inet 192.168.HS.X+20 netmask 0xffffff00 broadcast 192.168.HS.255 vhid X carp: MASTER vhid X advbase 1 advskew 0 peer 224.0.0.18 peer6 ff02::12 media: Ethernet autoselect (1000baseT <full-duplex>) status: active nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
Backup
em0: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500 description: LAN (lan) options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG> ether 08:00:27:1c:44:8b inet 192.168.1.2 netmask 0xffffff00 broadcast 192.168.1.255 inet 192.168.1.3 netmask 0xffffff00 broadcast 192.168.1.255 vhid 100 carp: BACKUP vhid 100 advbase 1 advskew 100 peer 224.0.0.18 peer6 ff02::12 media: Ethernet autoselect (1000baseT <full-duplex>) status: active nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
em1: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500 description: WAN (wan) options=48500b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,HWSTATS,MEXTPG> ether 08:00:27:95:9b:4b inet 192.168.HS.X+60 netmask 0xffffff00 broadcast 192.168.HS.255 inet 192.168.HS.X+20 netmask 0xffffff00 broadcast 192.168.HS.255 vhid X carp: BACKUP vhid X advbase 1 advskew 100 peer 224.0.0.18 peer6 ff02::12 media: Ethernet autoselect (1000baseT <full-duplex>) status: active nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
- Der Master hat advskew 0, das Backup advskew 100. Diesen Wert setzt OPNsense beim Sync automatisch – er wird nicht von Hand vergeben.
Wird Synchronisiert?
- Master
- System
- High Availability
- Status
- Synchronize and reconfigure all (Push)
- Status
- High Availability
- Backup
tail -f /var/log/configd/latest.log
- Hier sollte man die Übertragung sehen.
