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

החלפה אחת, שני שינויים נפרדים

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

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

מה המאמת בודק, לפי הסדר

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

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

openssl verify -CAfile new-ca.crt gateway.crt
openssl verify -CAfile new-ca.crt -untrusted intermediate.crt client.crt
openssl x509 -in gateway.crt -noout -subject -issuer -dates
openssl s_client -connect gw.example.net:443 -CAfile new-ca.crt

הפקודה הזו עובדת רק מול מאזין TLS פשוט כמו עמוד הניהול ב-HTTPS של השער; ערוץ הבקרה של OpenVPN קודם ל-TLS, ולכן s_client אינו יכול לבחון את לחיצת היד של המנהרה.

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

מדוע המנהרה הישנה ממשיכה לעבוד

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

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

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

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

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

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

סיבוב שלא מפיל את הרשת

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

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

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

אמתו את התוצאה, לא את רשימת הקבצים

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

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

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

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