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

שלושת התנאים שקובעים זאת

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

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

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

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

מה כל מסלול קלט באמת עושה

--auth-user-pass לבדה מבקשת שם משתמש וסיסמה במסוף. כשניתן שם קובץ, הלקוח לוקח את השורה הראשונה כשם משתמש ואת השורה השנייה כסיסמה; שום דבר לא תומך במרכאות, בהערות או בתחביר מפתח-ערך. זה כל הפורמט, ולכן כל מי שעורך אותו בציפייה לקובץ INI שובר אותו. בלוק <auth-user-pass> מוטבע מכיל את אותן שתי שורות בתוך הפרופיל, מה שהופך את הפרופיל עצמו לסוד ומציב אותו באותה מחלקת טיפול כמו מפתח פרטי.

שני המסלולים האחרים הם זרם ו-socket. OpenVPN צריכה רק תיאור קובץ קריא, ולכן היא תקבל החלפת תהליך, רשומת /dev/fd מגובה בצינור או שם קובץ שהוא למעשה FIFO. ממשק הניהול שונה במהותו: הלקוח שואל תהליך מפקח על הערכים במקום לקרוא אותם בעצמו. ההבדל הזה חשוב בחיבור מחדש: קובץ אישורים, FIFO שעוזר סודות יכול לכתוב אליו שוב וממשק הניהול יכולים לספק מחדש בלי אדם; החלפת תהליך לא יכולה, כי התיאור נצרך בקריאה הראשונה.

הקובץ חייב להיות בדיוק שתי שורות

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

install -m 600 /dev/null /etc/openvpn/client.creds
printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS" > /etc/openvpn/client.creds
od -c /etc/openvpn/client.creds | head -3

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

בדקו את הקובץ לפני שאתם מאשימים את השרת. הרצת openvpn --config client.ovpn --auth-user-pass /etc/openvpn/client.creds --verb 4 מדפיסה אם הקובץ נפתח ובהמשך אם האישורים התקבלו, מה שאומר לכם איזו שכבה לשנות הלאה.

זרמים, stdin והשגיאות שהם מייצרים

העברת הסיסמה בצינור היא הדבר הראשון שרוב האנשים מנסים והמסלול עם הכי הרבה הפתעות. החלפת תהליך עובדת כי הלקוח צריך רק תיאור קריא: openvpn --config client.ovpn --verb 3 --auth-user-pass <(printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS"). העברת /dev/stdin עובדת רק כשה-stdin עדיין פתוח וקריא ברגע שהלקוח שואל, מה שלא נכון בצינור שכבר צרך אותו.

ל-ERROR: could not read Auth username from stdin יש שתי סיבות שונות. בחלק מלקוחות 2.3.x ההודעה נבעה מפגם בטיפול ב-stdin שתוקן במהדורות 2.3 מאוחרות יותר, כך שלקוח כה ישן משתפר רק בשדרוג. בלקוח מודרני אותה נוסחה אומרת שהלקוח ביקש קלט מהמסוף וה-stdin לא היה מסוף - בדיוק המצב ביחידת systemd, במשימת cron או בקונטיינר שהופעל בלי -t.

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

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

בקר שכבר מפקח על המנהרה יכול גם לענות על שאלותיה. הפעילו את הלקוח עם --management 127.0.0.1 7505, קראו את שורות המצב ועקבו אחרי >PASSWORD:Need 'Auth' username/password. הבקר עונה עם username "Auth" alice ואחריו password "Auth" ... בשורות פקודה נפרדות. אסימון 'Auth' מחזיר את המזהה מהבקשה וחייב להתאים, אחרת התשובה מתעלמת והלקוח ממתין.

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

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

לחיצת יד TLS שלעולם לא מסתיימת, או VERIFY ERROR: depth=0, error=certificate signature failure, היא בעיית אמון ומתרחשת לפני שנקרא שם משתמש כלשהו. לקוח proto tcp שמכוון למאזין UDP נכשל באותו מקום: החבילות לעולם לא מגיעות לשלב האימות, ולכן כל סיסמה נראית שגויה מתוך אסוציאציה. השאירו את אימות האישורים דלוק לפני שהאישור נשלח; בקשה מוכרת לא אומרת דבר על מי מקבל את הסיסמה. בדקו את שרשרת האישורים, את השם הנפוץ ואת התעבורה לפני שאתם נוגעים באישור.

באגים ב-shell בסקריפט שמרכיב את הפרופיל הם העקבות הכוזבות האחרות. רווח חסר בתוך [ ! -f "$file" ] מייצר command not found, הסקריפט נעצר מוקדם, הפרופיל לא נבנה מחדש והלקוח מופעל עם הקודם. השגיאה הזו שייכת ל-shell, לא לאימות, ושום הקלדה מחדש של הסיסמה לא תמחק אותה.

לא כל בקשה בזרימה הזו היא האישור הזה. סיסמת מפתח פרטי, התחברות דרך פרוקסי HTTP וסיסמת השירות הם שלושה סודות שונים שנדרשים בשלבים שונים, וסיסמת מפתח בדרך כלל מטופלת על ידי הלקוח או סוכן ולא על ידי auth-user-pass. אם הבקשה מופיעה לפני שה-session של TLS עולה, אתם עונים על השאלה הלא נכונה ושום איפוס חשבון לא יעזור. לאחר שהבקשה השגויה הוסרה, הבדיקות הנותרות מתחילות בשכבה המוקדמת ביותר:

  • קראו את שגיאת הפרוטוקול הראשונה, לא את שורת האישורים האחרונה: TLS, אחר כך אימות, אחר כך push.
  • ודאו שהקובץ הוא שתי שורות, שאין בו החזרות עגלה ושהוא מופנה בנתיב מוחלט.
  • ודאו שהפרופיל ושורת הפקודה לא חלוקים על ההוראה.
  • הפרידו בין "האישורים התקבלו" לבין "התעבורה זורמת" - ניתוב ו-DNS הם שכבה מאוחרת יותר.

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

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