שני האתרים משתמשים באותו טווח LAN, והחפיפה היא לא מה שבאמת שובר את העיצוב. הרכזת חייבת לבחור אתר לפי כתובת היעד בלבד, ושתי יעדים זהים לא נותנים לה דבר לבחור לפיו. מספור מחדש של משרד עובד כדי לספק מנהרה הוא בדרך כלל עסקה גרועה יותר מלתת לכל שירות מפורסם כתובת נפרדת שהמנהרה יכולה לשאת. העיצוב שלהלן מפרסם שירות HTTPS אחד לכל אתר ולא דבר אחר.

למה החפיפה היא לא הבעיה האמיתית

WireGuard מעביר לפי יעד: ה-AllowedIPs של peer קובע איזה peer יקבל מנה. שני peers לא יכולים שניהם להכריז על 10.10.7.0/24 בלי שאחד מהם ינצח בכל חיפוש. זו תכונה של טבלת ה-peers ולא של המנהרה, ולכן הפתרון כאן הוא תוכנית כתובות ולא טריק ניתוב.

התוכנית היא להפסיק להכריז על ה-LAN לגמרי. הכריזו במקום זאת על כינוי לכל שירות, כתובת אחת לכל אתר, ותנו לשער של כל אתר לתרגם את הכינוי הזה לאפליקציה האמיתית שלו.

המשתמש מנתב שתי כתובות ייחודיות, לא רואה לעולם את התחילית הדו-משמעית, ושום דבר לא משתנה באף אחד משני המשרדים. זה גם מצהיר על הגבול בכנות: אתם מפרסמים שירות HTTPS אחד מכל אתר, לא ממזגים שני רשתות. הכללים שלהלן נשארים קטנים כי ההצהרה צרה. הצהרה רחבה יותר תדרוש כללים רחבים יותר, וכך העיצובים האלה הופכים מסובכים.

תנו לכל אתר כינוי שהמשתמש יכול לנתב

בחרו כתובות מטווח שלא מתנגש עם דבר במחשב של המשתמש, ברכזת או באף אחד משני ה-LAN. כאן הרכזת היא 10.66.0.1, המשתמש הוא 10.66.0.10, השערים הם 10.66.0.21 ו-10.66.0.22, ושני הכינויים הם 10.77.1.20 ו-10.77.2.20. הרכזת מפרסמת כל כינוי דרך ה-peer שמחזיק בו, כך שמנה יוצאת המופנית לכינוי אחד יכולה לצאת רק דרך האתר המתאים:

[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

צד המשתמש צריך רק את שני הכינויים, מה שמשאיר את תצורת הלקוח נקייה משתי התחיליות של ה-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 בקישור העליון של האתר; הוא לא מאשר תעבורה, והחומה עדיין מחליטה מה מותר. העתקת התצורה של שער אחד לשני היא בסדר כל עוד המפתח הפרטי, כתובת הממשק והכינוי כולם משתנים.

מה הרכזת חייבת להתיר בין שניים מה-peers שלה

הרכזת מעבירה מנות בין שניים מה-peers של עצמה, וזו החלטה בשרשרת forward ולא החלטת קלט. הפעילו העברת IPv4 דרך המנגנון הרגיל של הפלטפורמה, ואז התירו בדיוק את הזוגות שהעיצוב צריך.

הכלל שלהלן מתיר למשתמש כינוי אחד ופורט אחד, ומתיר תעבורת חזרה דרך מעקב חיבורים. הוא מפיל כל דבר אחר בנתיב 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 באחרת, אז מזגו את זה עם המדיניות הקיימת במקום לטעון אותו לצידה. וכתובת המקור מזהה את המכשיר, לא את האדם; הפרידו את אימות האפליקציה מקבילת הרשת.

איפה כינוי הופך לכתובת אמיתית

אתר A מקבל בקשה ל-10.77.1.20, כותב מחדש את היעד לאפליקציה האמיתית, וכותב מחדש את המקור לכתובת ה-LAN של עצמו כדי שהתשובה תוכל לחזור בלי מסלול למנהרה. עשיית שני התרגומים במקום אחד משאירה את שאר הרשת בורה לגבי הכינוי. הכללים שלהלן הם כל המנגנון:

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, בתוספת כיוון החזרה. וו ה-forward רואה את היעד אחרי תרגום היעד ולפני כתיבת המקור מחדש, ולכן הכלל נוקב בכתובת האפליקציה האמיתית. קראו את שני הווים האלה בסדר הזה בכל פעם שכלל נראה כאילו אינו מתאים לשום דבר. כלל forward שנכתב נגד הכינוי לא יכול להתאים לעולם, כי הכינוי כבר לא קיים בוו הזה.

אתר B חוזר על זה עם הכינוי ועם המפתח של עצמו. אסור לו לעשות שימוש חוזר במפתח הפרטי של אתר A, כי שני peers שחולקים זהות אחת הם שגיאת תצורה שקשה לראות וקלה ליצור על ידי העתקת קובץ. שמרו את שני מסמכי השער זהים פרט לערכים שחייבים להיות שונים, כדי שההבדל יבלוט בסקירה. קובץ מועתק הוא המקור הרגיל לתקלה הזו.

לכתיבת המקור מחדש יש מחיר. האפליקציה רואה את השער כלקוח שלה, ולכן הלוגים שלה כבר לא מראים איזה משתמש התחבר. שמרו את נתיב הביקורת של השער, ואל תחלישו את הכניסה לאפליקציה כדי לפצות על זהות רשת שהתרגום הסיר.

איך להוכיח ששני השמות המפורסמים עונים

תנו לכל כינוי שם 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/

כינוי ריק או בלתי צפוי בפקודה הראשונה אומר שבחירת ה-peer שגויה עוד לפני שכלל חומה כלשהו חשוב. אם הכינוי נכון והשם עדיין נכשל, הבעיה עברה ל-DNS ולתעודות. ברגע ששני השמות עונים והפורט השלישי נשאר סגור, העיצוב עושה את מה שהוא מצהיר: שני שירותים מפורסמים בצמצום, לא שני LAN ממוזגים.

מאמרים קשורים