--reconnect-timeout עונה על שאלה צרה אחת: לאחר שהמנהרה נופלת, כמה זמן תהליך הלקוח הזה ממשיך לנסות לפני שהוא מוותר ויוצא. עמוד המדריך של OpenConnect מתעד את האפשרות הזו עם ברירת מחדל מתועדת של 300 שניות לניסיונות חוזרים שבאים לאחר קישור שאבד או עמית שהפסיק להשיב, והמספר הוא מועד אחרון ללקוח פועל אחד, לא הוכחה שה-VPN נשאר נגיש. הוא גם אינו מדיניות לשמירת התהליך בחיים, ושם מתחילה רוב הבלבול.

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

מה חלון החיבור מחדש באמת תוחם

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

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

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

הפעלות מחדש של המפקח וניסיונות חוזרים של הלקוח הם שני רבדים

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

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

sudo openconnect --background --pid-file=/run/openconnect/vpn.pid \
  --reconnect-timeout=180 \
  --user=<account> https://vpn.example.edu

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

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

למנוע מהמסירה להתחרות בלופ הניסיונות החוזרים

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

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

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

מה לאמת במהלך הפסקה ואחריה

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

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

curl -sS --max-time 5 -o /dev/null -w '%{http_code}\n' https://intranet.example.internal/health
cat /run/openconnect/vpn.pid
ps -o pid,etime,cmd -p "$(cat /run/openconnect/vpn.pid)"

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

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

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