קובץ אישורים או שקע ניהול של OpenVPN: מה לתסרט
auth-user-pass מכסה את בקשת החשבון; שקע הניהול מכסה את כל הארבע. השוו את החשיפה, עלות התסריט ואיך כל אחד נכשל בשירות.
סקריפט שמפעיל את OpenVPN ואף פעם לא מתחבר אינו בדרך כלל בעיית רשת: הלקוח יושב מול בקשה בלי מסוף שעליו לצייר אותה. OpenVPN מציע בדיוק שתי דרכים נתמכות לענות על הבקשה הזו בלי אדם, קובץ אישורים מאחורי auth-user-pass ושקע הניהול, והן אינן ניתנות להחלפה. הקובץ עולה הוראה אחת ועונה על בקשה אחת; השקע עונה על כל בקשה ונותן לכל דבר שיכול לפתוח פורט loopback ערוץ שליטה לא מאומת. איזה מהם מתאים לפריסה שלכם תלוי באיזו בקשה באמת חוסמת, ובאיזה סוד אתם יכולים להרשות לעצמכם להשאיר במנוחה.
תנו שם לבקשה לפני שאתם בוחרים מנגנון
ארבע בקשות נראות זהות במסוף. צמד החשבון מגיע מהגדרת PAM או auth-user-pass-verify של השרת ועליו עונה auth-user-pass. סיסמת מפתח פרטי שייכת לקובץ המפתח ונקראת דרך --askpass או מוקלדת ביד. חבילת PKCS#12 מבקשת סיסמה משלה. אימות פרוקסי משתמש בקובץ auth של --http-proxy, לא באישורי החשבון.
כאשר OpenVPN רץ כתהליך בן של systemd, PHP או Node אין מסוף, ולכן כל אחת מהן חוסמת בשקט. התהליך נשאר שם, היומן נעצר אחרי שורת ההצפנה, והיחידה בסוף פוגעת בפסק זמן; השקט הזה הוא הסיבה שאנשים מוסיפים לולאת ניסיון חוזר או sleep במקום להסתכל איזו בקשה ממתינה. רק שקע הניהול יכול לענות על כל הארבע. קובץ האישורים עונה על הראשונה ושום דבר אחר.
auth-user-pass: קובץ אחד, בקשה אחת
הקובץ מחזיק את שם המשתמש בשורה הראשונה ואת הסיסמה בשורה השנייה, ושום דבר אחר: בלי מרכאות, בלי שמות מפתחות, בלי הערה. קבעו מצב 600 והפכו לבעלים את החשבון שמריץ את openvpn, שלשירות הוא לעיתים קרובות משתמש ייעודי ולא הכניסה שלכם. קובץ בבעלות root תחת /root הוא ההבדל בין פקודה שעובדת במעטפת שלכם לבין יחידה שנכשלת באתחול.
שני פרטים הופכים קובץ תקין לבקשה. עורך ששומר CRLF משאיר החזרת קרונית דבוקה לסיסמה, ולכן השרת דוחה סיסמה שנראית נכונה בקובץ; בדקו עם cat -A או od -c ולא בעין. ו-auth-user-pass בלי ארגומנט בתוך הפרופיל פירושו «שאל את המשתמש» לפי התכנון, שאולי הוראה שנייה בשורת הפקודה לא תעקוף, מפני שהפרופיל מנותח במקום שבו הוא נמצא.
סדר האפשרויות הוא המלכודת השלישית, והוא תלוי גרסה. כמה גרסאות בנייה של OpenVPN 2.4 מתעלמות מהאפשרות --auth-user-pass כשהיא מופיעה לפני --config, ולכן אותן שתי אפשרויות בסדר ההפוך מתחברות. שימו את ההוראה בתוך הפרופיל, או אחרי --config בשורת הפקודה, וחפשו בפרופיל כל מופע לפני שתשנו משהו אחר.
auth-nocache שייך למנגנון הזה אבל לא מספק דבר. הוא מגביל כמה זמן הלקוח מחזיק את האישור בזיכרון, מה שעוזר אחרי קריסה ולא עוזר בכלל כשהקובץ חסר. התחברות מחדש אחרי פסק זמן של הפעלה בצד השרת קוראת את הקובץ שוב, ולכן אישור שעבד באתחול עדיין יכול לפוג באמצע היום.
שקע הניהול: כל בקשה, יותר שטח פנים
הפעילו את הלקוח עם מאזין והצהירו במפורש שבקשות ידווחו עליו, באמצעות ההוראות שמתועדות במדריך OpenVPN 2.6:
management 127.0.0.1 3030
management-query-passwords
מ-bash החזיקו את החיבור על מתאר קובץ פנוי והשיבו לפי שם הבקשה ולא לפי מיקום, מפני שהתחברות מחדש יכולה לשאול בסדר אחר:
exec 3<>/dev/tcp/127.0.0.1/3030
while read -r -u 3 line; do
case "$line" in
*"Need 'Auth' username/password"*)
echo 'username "Auth" alice' >&3
echo 'password "Auth" secret' >&3 ;;
*"Need 'Private Key' password"*)
echo 'password "Private Key" secret' >&3 ;;
esac
done
הגבול הוא התעבורה. פרוטוקול הניהול הוא טקסט גלוי מעל TCP על loopback, ולכן אסור לפרסם את המאזין בכתובת LAN או מנהרה כדי שבקר מרוחק יגיע אליו; בקר מרוחק פירושו העברת SSH, לא כריכה רחבה יותר. הדמון הקהילתי מקבל גם לקוח ניהול אחד בכל פעם, ולכן GUI או צג אינם יכולים לחלוק את השקע עם הסקריפט שלכם. החיבור השני נדחה, לא נכנס לתור, והכשל נראה כמו סקריפט שהתחרש.
השקע הזה הוא גם ערוץ שליטה. בלי סיסמת ניהול, כל דבר שיכול להתחבר אל 127.0.0.1:3030 יכול לקרוא מצב, להרוג את המנהרה או לענות בעצמו על בקשה. סיסמת הניהול וקובץ האישורים הם סוד מאותה דרגה, ושניהם ראויים לאותה זהירות.
איזה מתאים לפריסה
בחרו בקובץ האישורים כשהבקשה היחידה היא צמד החשבון, הלקוח רץ כשירות עם בעלים יציב, ואתם יכולים להחזיק קובץ 600 מחוץ לגיבויים שאינכם שולטים בהם. בחרו בשקע הניהול כשסיסמת מפתח או סיסמת PKCS#12 עומדות על הפרק, כשהעטיפה כבר מפקחת על התהליך, או כשאתם צריכים לצפות במצב ובבקשות בזמן ניפוי התחברות מחדש.
שני תנאים מזיזים את ההחלטה. אם העטיפה היא /bin/sh, יחידת systemd שקוראת לקובץ הבינארי ישירות, או מכולה מינימלית, דבק השקע ל-bash בלבד אינו זמין והקובץ הוא התשובה הזולה יותר. אם הסוד מתחלף לעיתים קרובות, אף קובץ אינו בית טוב עבורו: שאלו מחזיק מפתחות מעטיפה קטנה ותנו ליחידה לקרוא לעטיפה, מה שמשאיר את ההחלפה במקום אחד ואת הסיסמה מחוץ להיסטוריית המעטפת.
החלפת תהליכים עומדת בין השניים ואינה שייכת לאף אחד מהם. שורת הפקודה למטה עובדת מפני ש-bash מרחיב אותה לפני ש-openvpn מתחיל, לא מפני שהלקוח מבין את התחביר:
openvpn --config client.ovpn --auth-user-pass <(printf "%s
%s
" "$USER" "$PASS")
היא נשברת תחת /bin/sh, ביחידה שעוקפת את המעטפת, ובתמונות בלי bash או /dev/fd. שמרו אותה לבדיקות אינטראקטיביות, ולעולם לא כחוזה ששירות תלוי בו.
הגנו על הסוד, ואז אמתו מהיומן
שני המנגנונים משאירים סוד קריא לתהליך OpenVPN. לעולם אל תשימו את הסיסמה בשורת הפקודה או בקובץ היחידה, שם ps ו-systemctl מציגים אותה לכל משתמש מקומי; העבירו את הנתיב לקובץ, לא את הערך שבתוכו. במקום שבו תעודות יכולות להחליף את צמד החשבון, זה מסיר את קטגוריית הבקשה במקום להסתיר אותה.
הרצה תקינה מראה את רצף הבקשות מושלם וההפעלה מגיעה אל «Initialization Sequence Completed». אם הלקוח עוצר באותה בקשה, ההתאמה נכשלה: הדפיסו את השורות המדויקות שהשקע שלח, בדקו את המרכאות ואת שם הבקשה, ותקנו את התבנית במקום להוסיף sleep. מנהרה שמדווחת על הצלחה ולא מעבירה דבר היא בעיית ניתוב או push, לא בעיית אישורים.
ואז בדקו את ההתחברות מחדש, לא רק את האתחול הראשון. הפילו את ההפעלה בצד השרת או המתינו לפסק הזמן שלה; הלקוח שואל שוב, ושם בדיוק קובץ שנראה תקין באתחול מראה אם הוא עדיין קריא לחשבון שמתחבר מחדש.