Και οι δύο τοποθεσίες χρησιμοποιούν το ίδιο εύρος LAN, και η επικάλυψη δεν είναι αυτό που πραγματικά χαλάει τον σχεδιασμό. Ο κόμβος πρέπει να επιλέγει τοποθεσία μόνο με τη διεύθυνση προορισμού, και δύο πανομοιότυποι προορισμοί δεν του δίνουν τίποτα για να επιλέξει. Η επαναρίθμηση ενός γραφείου που λειτουργεί για να εξυπηρετήσει ένα τούνελ είναι συνήθως χειρότερη ανταλλαγή από το να δώσετε σε κάθε δημοσιευμένη υπηρεσία μια ξεχωριστή διεύθυνση που το τούνελ μπορεί να μεταφέρει. Ο σχεδιασμός παρακάτω δημοσιεύει μία υπηρεσία HTTPS ανά τοποθεσία και τίποτε άλλο.

Γιατί η επικάλυψη δεν είναι το πραγματικό πρόβλημα

Το WireGuard προωθεί με βάση τον προορισμό: τα AllowedIPs ενός peer καθορίζουν ποιος peer λαμβάνει ένα πακέτο. Δύο peers δεν μπορούν να διαφημίζουν και οι δύο το 10.10.7.0/24 χωρίς ένας από αυτούς να κερδίζει κάθε αναζήτηση. Αυτό είναι ιδιότητα του πίνακα peers και όχι του τούνελ, γι' αυτό η λύση εδώ είναι ένα σχέδιο διευθύνσεων και όχι ένα κόλπο δρομολόγησης.

Το σχέδιο είναι να σταματήσουμε εντελώς να διαφημίζουμε το LAN. Διαφημίστε αντ' αυτού ένα alias ανά υπηρεσία, μία διεύθυνση ανά τοποθεσία, και αφήστε την πύλη κάθε τοποθεσίας να μεταφράζει αυτό το alias στην πραγματική της εφαρμογή.

Ο χρήστης δρομολογεί δύο μοναδικές διευθύνσεις, δεν βλέπει ποτέ το διφορούμενο πρόθεμα, και τίποτα δεν αλλάζει σε κανένα από τα δύο γραφεία. Αυτό δηλώνει και το όριο με ειλικρίνεια: δημοσιεύετε μία υπηρεσία HTTPS από κάθε τοποθεσία, δεν συγχωνεύετε δύο δίκτυα. Οι κανόνες που ακολουθούν μένουν μικροί επειδή η δήλωση είναι στενή. Μια ευρύτερη δήλωση θα χρειαζόταν ευρύτερους κανόνες, και έτσι ακριβώς αυτοί οι σχεδιασμοί γίνονται πολύπλοκοι.

Δώστε σε κάθε τοποθεσία ένα alias που ο χρήστης μπορεί να δρομολογήσει

Επιλέξτε διευθύνσεις από ένα εύρος που δεν συγκρούεται με τίποτα στο μηχάνημα του χρήστη, στον κόμβο ή σε οποιοδήποτε από τα δύο LAN. Εδώ ο κόμβος είναι 10.66.0.1, ο χρήστης 10.66.0.10, οι πύλες 10.66.0.21 και 10.66.0.22, και τα δύο alias 10.77.1.20 και 10.77.2.20. Ο κόμβος δημοσιεύει κάθε alias μέσω του peer που το κατέχει, οπότε ένα εξερχόμενο πακέτο προς ένα alias μπορεί να φύγει μόνο μέσω της αντίστοιχης τοποθεσίας:

[Interface]
Address = 10.66.0.1/32
ListenPort = 51820
PrivateKey = HUB_KEY

[Peer]
PublicKey = USER_PUBLIC_KEY
AllowedIPs = 10.66.0.10/32

[Peer]
PublicKey = SITE_A_PUBLIC_KEY
AllowedIPs = 10.66.0.21/32, 10.77.1.20/32

[Peer]
PublicKey = SITE_B_PUBLIC_KEY
AllowedIPs = 10.66.0.22/32, 10.77.2.20/32

Η πλευρά του χρήστη χρειάζεται μόνο τα δύο alias, κάτι που κρατά τη διαμόρφωση του πελάτη ελεύθερη και από τα δύο προθέματα LAN. Τίποτα σε αυτή τη διαμόρφωση δεν αναφέρει κανένα από τα πραγματικά LAN:

[Interface]
Address = 10.66.0.10/32
PrivateKey = USER_KEY

[Peer]
PublicKey = HUB_PUBLIC_KEY
Endpoint = hub.example.net:51820
AllowedIPs = 10.77.1.20/32, 10.77.2.20/32
PersistentKeepalive = 25

Κάθε πύλη διαφημίζει τον κόμβο και την πηγή του χρήστη, τίποτε άλλο, ώστε μια τοποθεσία να μη μαθαίνει ποτέ το LAN της άλλης. Το keepalive διατηρεί μια αντιστοίχιση NAT στο uplink της τοποθεσίας· δεν εξουσιοδοτεί κίνηση, και το firewall εξακολουθεί να αποφασίζει τι γίνεται δεκτό. Η αντιγραφή της διαμόρφωσης μιας πύλης στην άλλη είναι εντάξει αρκεί να αλλάζουν το ιδιωτικό κλειδί, η διεύθυνση της διεπαφής και το alias.

Τι πρέπει να επιτρέπει ο κόμβος ανάμεσα σε δύο peers του

Ο κόμβος προωθεί πακέτα ανάμεσα σε δύο δικούς του peers, κάτι που είναι απόφαση στην αλυσίδα forward και όχι απόφαση εισόδου. Ενεργοποιήστε την προώθηση IPv4 με τον συνήθη μηχανισμό της πλατφόρμας και μετά επιτρέψτε ακριβώς τα ζεύγη που χρειάζεται ο σχεδιασμός.

Ο κανόνας παρακάτω επιτρέπει στον χρήστη ένα alias και μία θύρα, και επιτρέπει την κίνηση επιστροφής μέσω παρακολούθησης συνδέσεων. Απορρίπτει όλα τα άλλα στη διαδρομή forward, και αυτό είναι το νόημα:

nft add table inet hub_transit
nft add chain inet hub_transit forward '{ type filter hook forward priority 0 ; policy drop ; }'
nft add rule inet hub_transit forward ct state established,related accept
nft add rule inet hub_transit forward iifname wg0 oifname wg0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.77.1.20 accept

Δύο λεπτομέρειες αξίζει να αναφερθούν γιατί προκαλούν σιωπηλές αποτυχίες. Ένα accept σε μία βασική αλυσίδα δεν υπερισχύει ενός drop σε άλλη, οπότε συγχωνεύστε το με την υπάρχουσα πολιτική αντί να το φορτώσετε δίπλα. Και η διεύθυνση πηγής προσδιορίζει τη συσκευή, όχι το πρόσωπο· κρατήστε τον έλεγχο ταυτότητας της εφαρμογής ξεχωριστό από την αποδοχή στο δίκτυο.

Όπου ένα alias γίνεται πραγματική διεύθυνση

Η τοποθεσία A λαμβάνει αίτημα για το 10.77.1.20, ξαναγράφει τον προορισμό στην πραγματική εφαρμογή και ξαναγράφει την πηγή στη δική της διεύθυνση LAN ώστε η απάντηση να μπορεί να επιστρέψει χωρίς διαδρομή προς το τούνελ. Το να γίνονται και οι δύο μεταφράσεις σε ένα σημείο κρατά το υπόλοιπο δίκτυο ανήξερο για το alias. Οι κανόνες παρακάτω είναι ολόκληρος ο μηχανισμός:

nft add table ip site_a_nat
nft add chain ip site_a_nat pre '{ type nat hook prerouting priority -100 ; policy accept ; }'
nft add chain ip site_a_nat post '{ type nat hook postrouting priority 100 ; policy accept ; }'
nft add rule ip site_a_nat pre iifname wg0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.77.1.20 dnat to 10.10.7.20:443
nft add rule ip site_a_nat post iifname wg0 oifname lan0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.10.7.20 snat to 10.10.7.2

Η πολιτική forward της τοποθεσίας A πρέπει έπειτα να δέχεται τη μεταφρασμένη ροή από τη διεπαφή του τούνελ στη διεπαφή LAN, μαζί με την κατεύθυνση επιστροφής. Το hook forward βλέπει τον προορισμό μετά τη μετάφραση προορισμού και πριν την επανεγγραφή της πηγής, γι' αυτό ο κανόνας ονομάζει τη διεύθυνση της πραγματικής εφαρμογής. Διαβάστε αυτά τα δύο hooks με αυτή τη σειρά όποτε ένας κανόνας φαίνεται να μην ταιριάζει με τίποτα. Ένας κανόνας forward γραμμένος απέναντι στο alias δεν μπορεί ποτέ να ταιριάξει, γιατί το alias δεν υπάρχει πια σε εκείνο το hook.

Η τοποθεσία B το επαναλαμβάνει με δικό της alias και δικό της κλειδί. Δεν πρέπει να ξαναχρησιμοποιήσει το ιδιωτικό κλειδί της τοποθεσίας A, γιατί δύο peers που μοιράζονται μία ταυτότητα είναι σφάλμα διαμόρφωσης που είναι δύσκολο να δεις και εύκολο να δημιουργήσεις αντιγράφοντας ένα αρχείο. Κρατήστε τα δύο έγγραφα πύλης πανομοιότυπα εκτός από τις τιμές που πρέπει να διαφέρουν, ώστε η διαφορά να ξεχωρίζει στην ανασκόπηση. Ένα αντιγραμμένο αρχείο είναι η συνήθης προέλευση αυτού του σφάλματος.

Η επανεγγραφή της πηγής έχει κόστος. Η εφαρμογή βλέπει την πύλη ως πελάτη της, οπότε τα αρχεία καταγραφής της δεν δείχνουν πια ποιος χρήστης συνδέθηκε. Κρατήστε το ίχνος ελέγχου της πύλης, και μην αποδυναμώσετε τη σύνδεση της εφαρμογής για να αντισταθμίσετε μια ταυτότητα δικτύου που αφαίρεσε η μετάφραση.

Πώς να αποδείξετε ότι και τα δύο δημοσιευμένα ονόματα απαντούν

Δώστε σε κάθε alias ένα όνομα DNS και διαμορφώστε την εφαρμογή και το πιστοποιητικό για αυτό το όνομα, γιατί η μετάφραση δεν ξαναγράφει ανακατευθύνσεις ή ενσωματωμένα απόλυτα URL. Χρησιμοποιήστε ένα όνομα ανά τοποθεσία ώστε μια ασυμφωνία πιστοποιητικού να μην μπορεί ποτέ να εκληφθεί ως σφάλμα δρομολόγησης.

Δοκιμάστε από τον πραγματικό πελάτη, επιβεβαιώστε ποια τοποθεσία απάντησε, και δοκιμάστε και μια μη εξουσιοδοτημένη θύρα. Χρησιμοποιήστε νέες συνδέσεις μετά από οποιαδήποτε αλλαγή NAT, γιατί η εδραιωμένη κατάσταση κρατά την παλιά αντιστοίχιση:

wg show wg0 allowed-ips
sudo nft list ruleset
curl -sS -o /dev/null -w "%{http_code}\n" https://site-a.example.net/

Ένα κενό ή απρόσμενο alias στην πρώτη εντολή σημαίνει ότι η επιλογή peer είναι λάθος πριν μετρήσει οποιοσδήποτε κανόνας firewall. Αν το alias είναι σωστό και το όνομα εξακολουθεί να αποτυγχάνει, το πρόβλημα μετακινήθηκε στο DNS και στα πιστοποιητικά. Μόλις απαντήσουν και τα δύο ονόματα και η τρίτη θύρα μείνει κλειστή, ο σχεδιασμός κάνει αυτό που ισχυρίζεται: δύο στενά δημοσιευμένες υπηρεσίες, όχι δύο συγχωνευμένα LAN.

Σχετικά άρθρα