מישהו מפנה מארח HAProxy ציבורי לאפליקציה פנימית ושואל למה הדפדפן לא יכול לעקוב. ה-proxy מגיע לאפליקציה דרך ה-VPN שלו, ההפניה מחזירה כותרת Location, והדפדפן מנסה אז כתובת שקיימת רק בתוך המנהרה. מבחוץ הדף פשוט נתקע. ההחלטה היא איזה צד פותח את החיבור השני, וזה מה שמפריד בין הפניה לשרת אחורי.

שני מסלולים שנראים דומים בתצורה

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

GET /app        client -> proxy
302 Location    proxy  -> client   (http://10.40.0.20:8080/)
GET /app        client -> 10.40.0.20:8080   client network, no route

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

GET /app        client -> proxy
GET /app        proxy  -> 10.40.0.20:8080   over the VPN
response        proxy  -> client

תיעוד ההפניות של HAProxy משרטט בדיוק את הגבול הזה: לענות ללקוח בהפניה הוא פעולה שונה מהעברת הבקשה לשרת אחורי. שתי ההוראות נמצאות כמה שורות זו מזו בקובץ תצורה ומתנהגות אחרת לגמרי. האחת מסיימת את הבקשה, והשנייה מתחילה בקשה שנייה ששייכת ל-proxy.

מה הדפדפן צריך ומה ה-VPN של השרת לא נותן לו

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

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

כשרק ה-proxy יכול להגיע לאפליקציה

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

backend private_app
    mode http
    option httpchk GET /health
    server app1 10.40.0.20:8080 check

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

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

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

ההפניות של האפליקציה עצמה עדיין מצביעות פנימה

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

הגדירו את כתובת ה-URL החיצונית המתועדת של האפליקציה ואת אפשרויות ה-proxy שלה, ואז התאימו את כותרת Host למארח הווירטואלי ולציפיות התעודה. קובץ Cookie שמוגבל לשם הפנימי לא יחזור דרך השם הציבורי, ולולאת הכניסה שאחריה נקראת כבאג אימות. שנו קודם את כתובת ה-URL החיצונית, בדקו שוב מפרופיל דפדפן נקי, וצפו שהגדרות שהועברו חצי ייצרו כניסה שמצליחה והפעלה שמתה מיד.

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

החליטו איזה עיצוב באמת יש לכם

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

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

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

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

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