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

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

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

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

ConditionReverse tunnel fitsSomething else is needed
How many services must be reachable?One, or a small fixed set on loopbackAnything that needs many ports or dynamic discovery
Who connects, and how are they authenticated?Named administrators with their own hub accountsThird parties, or anything needing per-flow audit you do not control
Does the device's own LAN need to be reachable?NoYes, so a routed VPN or a managed platform is the honest answer

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

צד ה-hub: חשבון ממסר תחום

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

Match User relay-dev-7
    AuthenticationMethods publickey
    PubkeyAuthentication yes
    AllowTcpForwarding remote
    PermitListen 127.0.0.1:21022
    GatewayPorts no
    MaxSessions 0
    PermitTTY no
    X11Forwarding no
    AllowAgentForwarding no

MaxSessions 0 היא השורה המעניינת. היא דוחה הפעלות של מעטפת ותת-מערכות ובמקביל מתירה את ההעברה שהמכשיר צריך, כך שמפתח גנוב לא יכול להפוך לכניסה אינטראקטיבית. PermitListen מקבעת את כתובת המאזין והפורט בצד ה-hub, ו- GatewayPorts no מחזיקה אותו על loopback במקום לפתוח אותו לרשת שה-hub נמצא בה.

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

צד המכשיר: העברה שנכשלת בקול רם

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

ssh -NT \
    -o ExitOnForwardFailure=yes \
    -o ServerAliveInterval=30 \
    -o ServerAliveCountMax=3 \
    -R 127.0.0.1:21022:127.0.0.1:22 \
    [email protected]

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

ExitOnForwardFailure=yes גורם לפקודה לצאת כאשר לא ניתן להקים את המאזין המבוקש, כך שלולאת הפעלה מחדש אומרת לכם את האמת במקום להשאיר הפעלה שעובדת למחצה. היא לא אומרת דבר על בריאות שירות ה-SSH המקומי בהמשך, אז שלבו אותה עם מנהל תהליכים ובדיקת חיבור אמיתית מדי פעם.

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

גישת מנהל דרך ה-hub

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

ssh -J [email protected] -o HostKeyAlias=device-7 \
    -p 21022 [email protected]

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

קחו בעלות על מחזור החיים

הריצו את פקודת המכשיר תחת מנהל תהליכים עם מופע פעיל אחד בדיוק ומדיניות הפעלה מחדש שבחרתם בכוונה. אפשרויות ה-keepalive מזהות עמית מת; הן לא מחיות תהליך שיצא.

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

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

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