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

גלו למי שייך מרחב השמות של המנהרה

ב-Docker Desktop ל-macOS או Windows הקונטיינרים רצים בתוך מכונה וירטואלית של Linux. לקוח VPN שמותקן על שולחן העבודה יוצר מנהרה במערכת ההפעלה של שולחן העבודה, והמכונה הווירטואלית לא רואה אותה לעולם. שום תצורת קונטיינר לא מתקנת זאת, כי הממשק שהקונטיינר היה זקוק לו כלל לא קיים במרחב השמות שלו.

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

docker info --format '{{.OperatingSystem}}'
docker run --rm --net=host alpine ip route | head -5
docker run --rm alpine ip route | head -5

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

רשת מארח היא בדיקה, לא תכנון

הרצת קונטיינר עם רשת מארח, שאותה Docker מתעד כשיתוף מרחב השמות של רשת המארח, גורמת לו לרשת ישירות את ממשק המנהרה ואת המסלולים שלה. אם אותה בקשה תצליח אז, תיאוריית המסלולים מאושרת והכשל הוא בידוד מרחבי שמות ולא אישורים, DNS או כלל גישה.

docker run --rm --net=host curl -sS -o /dev/null -w '%{http_code}\n' https://api.internal/health

שמרו על זה כאבחון. רשת מארח מוותרת על פרסום פורטים ועל רוב הבידוד שרציתם מקונטיינר, וב-Docker Desktop «host» פירושו המכונה הווירטואלית ולא שולחן העבודה, לכן הצלחה או כשל שם עלולים להטעות אתכם אם תשכחו לאיזה מארח פניתם.

התקן tun וההרשאות שמגיעות איתו

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

sudo modprobe tun
docker run --rm -it --device /dev/net/tun --cap-add NET_ADMIN myvpn-client

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

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

NAT של הגשר משנה את המקור שה-VPN רואה

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

macvlan או ipvlan נותן לקונטיינר כתובת LAN במקום, מה שעוזר לגילוי ב-LAN וגורם לקונטיינר להיראות כעמית בסגמנט. הוא גם עוקף לגמרי את מנהרת המארח, כך שקונטיינר כזה לא יגיע לקידומות של VPN בלבד אלא אם ה-VPN נגיש גם מאותה LAN.

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

DNS הולך אחרי הדמון, לא אחרי המנהרה

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

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

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

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

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