NET_ADMIN בקונטיינר VPN: מה הוא יכול לשנות והיכן
היכולת מאפשרת שינויים בממשקים, בנתיבים ובחומת האש בתוך מרחב שמות רשת אחד. עם רשת המארח, מרחב השמות הזה הוא המחסנית של המארח עצמו.
NET_ADMIN היא היכולת של לינוקס שמאפשרת לתהליך לבצע ניהול רשת, ובקונטיינר היא עושה בדיוק את זה בתוך מרחב שמות הרשת שבו התהליך פועל. היא אינה רישיון לפתוח סוקט, ואינה תחליף להתקן או לנתיב. השאלה המעניינת אינה לעולם אם היכולת ניתנה, אלא איזה מרחב שמות מקבל את השינוי.
מה היכולת מכסה
בתוך מרחב השמות שלו, תהליך שמחזיק ב-NET_ADMIN יכול להעלות ולהוריד ממשקים, להקצות כתובות, להוסיף ולהסיר נתיבים ולכתוב כללי חומת אש, וזו קבוצת הפעולות אשר capabilities(7) אוסף תחת היכולת הזו. הוא יכול גם לכוונן הגדרות ברמת הממשק ששולטות באופן שבו הגרעין מתור את התעבורה ומסנן אותה. לקוח VPN זקוק בדרך כלל לכמה מהן בעת האתחול ולשום דבר אחר אחר כך. לכן רוב התמונות מבקשות טווח רחב יותר ממה שהן משתמשות בו.
פעולות מחוץ למרחב השמות הזה אינן מכוסות, והרשאות סמוכות נפרדות. קריאה וכתיבה של מנות גולמיות שייכות ל-NET_RAW, ויצירת התקן tun דורשת גם את היכולת וגם גישה לצומת ההתקן. תהליך שאין לו את ההתקן מקבל שגיאת הרשאה שנראית כמו בעיית רשת ואינה כזו.
מרחב השמות קובע את רדיוס הפגיעה
קונטיינר ברשת הגשר שלו מגיע ל-loopback שלו, לממשקים שלו ולטבלת הניתוב שלו. הענקת NET_ADMIN שם מאפשרת ללקוח ה-VPN לבנות מנהרה בלי לגעת בהחלטות הניתוב של המארח, וזה הסידור שרוב תמונות הקונטיינר מניחות.
העבירו את הקונטיינר הזה לרשת המארח וההענקה הזו עורכת כעת את הנתיבים של המארח ואת חומת האש שלו, כי לא נותר מרחב שמות נפרד. הלקוח שהיה אמור לנהל מנהרה אחת יכול אז להפנות מחדש את התעבורה של כל המכונה, וטעות בסקריפט הפירוק שלו משאירה למארח כללים שאיש לא כתב. שום דבר ביכולת עצמה לא השתנה; ההקשר השתנה. זו הסיבה שאותו קובץ compose מתנהג אחרת בשני מארחים.
שלושה תנאים מוקדמים שמתמזגים לאחד
כשלי אתחול בקונטיינרי VPN כוללים בדרך כלל אחד משלושה דברים נפרדים: היכולת, התקן המנהרה ותמיכת הגרעין בפרוטוקול. הענקת כל השלושה בבת אחת עובדת, והיא גם הופכת את הכשל הבא לבלתי ניתן לייחוס. קטע compose מינימלי מעניק את היכולת ומעביר את צומת ההתקן במפורש:
services:
vpn:
image: example/vpn-client:latest
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun
sysctls:
- net.ipv4.conf.all.src_valid_mark=1קראו את התיעוד של התמונה עצמה כדי לדעת אילו sysctl היא צריכה, כי sysctl בקונטיינר עשוי לדרוש הרשאה נוספת או הגדרה ברמת המארח. במקום שבו התמונה תומכת רק במצב מרחב משתמש, אין צורך בהתקן כלל ורשימת היכולות מתכווצת בהתאם.
העניקו את הפעולה הצרה, לא את המצב
מצב מיוחס מוסר כל יכולת ומרחיב את הגישה להתקנים בו-זמנית, ולכן הוא מסתיר איזה משלושת התנאים המוקדמים היה חסר. הוא גם הופך את אופני הכשל של הקונטיינר לבלתי ניתנים להבחנה משינויים במארח. העדיפו רשימה מפורשת גם כשהיא ארוכה יותר לכתיבה.
פריסות ללא root ובמרחבי שמות של משתמש משנות מה המשמעות של יכולת בפועל, משום שהתהליך יכול להחזיק בה רק בתוך מרחב שמות ממופה. העתקת רשימת יכולות מדוגמה עם root לסביבת הרצה ללא root וציפייה לאותו טווח היא דרך נפוצה לאבד אחר צהריים.
סודות שייכים להחלטה נפרדת. החזקה ב-NET_ADMIN אינה אומרת דבר על זהות העמית שהלקוח מציג, על אישורי הכניסה שהוא טוען או על אופן החלפתם. ניהול רשת אינו מספק אמון.
ודאו את השינוי ותעדו מדוע ההענקה קיימת
אמתו מה הקונטיינר קיבל בפועל לפני שאתם מנתחים את המנהרה. הבדיקה שלהלן מדווחת על היכולות שנוספו ועל מצב הרשת, ואז מציגה איך נראית רשימת הממשקים מבפנים:
docker inspect --format '{{.HostConfig.CapAdd}} {{.HostConfig.NetworkMode}} {{.HostConfig.Privileged}}' vpn
docker exec vpn sh -c 'grep CapEff /proc/self/status'
docker exec vpn ip -br addr
docker exec vpn ip routeאם היכולת קיימת ורשימת הממשקים עדיין ריקה, הלקוח נכשל לפני שהספיק ליצור משהו, והיומנים של הקונטיינר הם המקום הבא להסתכל בו. אם המנהרה קיימת אך התעבורה אינה זורמת, טבלת הניתוב שבתוך הקונטיינר עונה על השאלה הבאה.
בדקו גם את מסלול הפירוק, כי לקוח שכותב כללי חומת אש יכול להשאיר אותם מאחור. עצרו את הקונטיינר ובדקו שוב את מערך הכללים של המארח אם משתמשים ברשת המארח. הענקה שנדרשת רק לשתי שניות באתחול לא צריכה להיות מתוארת בקובץ compose כדרישה קבועה בלי הערה שמסבירה זאת.
כתבו את הסיבה לצד כל יכולת: איזו פעולה נזקקה לה ומה נכשל בלעדיה. ההערה הזו שורדת עדכוני תמונה, והיא ההבדל בין רשימת הרשאות שנסקרה לבין כזו שגדלה בהעתקה והדבקה.