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

התחל מהפעולה שנכשלה

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

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

מפה כל פעולה לסמכות אחת

הטבלה היא מפת התחלה, לא תחליף לתיעוד המימוש:

OperationUsual authorityWatch for
Create or configure tun/tapCAP_NET_ADMIN in the relevant namespaceCreating the device and opening it are separate steps
Add routes, rules, firewall entriesCAP_NET_ADMINSame capability, different namespace than you think
Open /dev/net/tunDevice permissions, not a capabilityGroup membership or a udev rule may be enough
Raw socketsCAP_NET_RAWNeeded by some user-space tunnel implementations
Bind a port below 1024CAP_NET_BIND_SERVICEIrrelevant for most modern tunnel ports

שתי השורות בטבלה הזו הן אלה שאנשים מבלבלים ביניהן. פתיחת /dev/net/tun היא שאלה של הרשאות קובץ; בקשה מהליבה להגדיר את מה שפתחת היא שאלה של יכולות. מתן CAP_NET_ADMIN לא מתקן צומת התקן שמשתמש השירות שלך לא יכול לקרוא, ותיקון הצומת לא נותן לך סמכות מסלול. בדוק את שניהם לפני שאתה משנה מי מהם.

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

קרא את ההקשר: שירות, מכולה או מעטפת

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

ביחידות systemd קרא מה באמת מיושם ולא מה שנראה שקובץ היחידה אומר: systemctl show -p CapabilityBoundingSet -p AmbientCapabilities מדווח את הערכים האפקטיביים, שאולי נקבעו על ידי drop-in ששכחת. בקש את הערך האפקטיבי, לעולם לא את המיועד. יכולות ambient חשובות כי שירות שאינו root מאבד יכולות לאורך exec בלעדיהן.

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

שים לב למה שקורה אחרי שההרשאות נופלות

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

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

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

תעד את ההרשאה ואת הסיבה לה

רשום את ההרשאה המדויקת, את הפעולה שהיא מאפשרת ואת השגיאה שהיא תיקנה. שורה אחת בהערות הפריסה — «CAP_NET_ADMIN במרחב השמות של הרשת של היחידה, נדרש לשינויי מסלול אחרי חיבור מחדש» — מספיקה כדי למנוע מהאדם הבא להרחיב שוב את ההרשאה.

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

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