בלוג
תוכנית עבודה צעד אחר צעד לבידוד Multi-Tenant ב-Docker
בודדו עומסי עבודה מרובי דיירים (Multi-Tenant) ב-Docker תוך שליטה בעלויות האחסון. למדו כיצד להגדיר namespaces, cgroups, מדיניות רשת והקשחת זמני ריצה.
סיכום
ניהול תשתית משותפת עבור קמפיינים מרובים של לקוחות או נכסי אינטרנט פנימיים יוצר לעיתים קרובות חיכוך מול ההנהלה הבכירה סביב עלויות אחסון ואבטחת מידע. קונטיינרים של Docker מספקים אלטרנטיבה קלת משקל למכונות וירטואליות ייעודיות, אך הגדרות ברירת המחדל מותירות פערי בידוד חמורים. סביבת מרובת דיירים (Multi-Tenancy) אמיתית דורשת גבולות מוגדרים היטב ברמות הקרנל, התהליכים, הרשת והאחסון. מדריך זה מספק מסגרת מעשית בת חמישה שלבים לאבטחת פריסות Docker מרובות דיירים באמצעות מנגנוני בידוד מובנים של Linux. תלמדו כיצד לאכוף מכסות משאבים, להגביל הרשאות תהליכים, לפלח רשתות קונטיינרים ולבחור את רמת הבידוד הנכונה. מעקב אחר תוכנית זו יאפשר לכם להגן על סביבות הדיירים ולהצדיק את תקציבי התשתית בפני גורמים ניהוליים שאינם טכניים.
המנהל שלכם נכנס למשרד עם הדפסה של חשבונית אחסון הענן מהחודש שעבר. העלויות זינקו, ובמקביל מספר דפי נחיתה בעדיפות גבוהה סבלו מבעיות שיהוי (latency) חמורות במהלך השקת מוצר. אתם מתבקשים להסביר מדוע נכסים שיווקיים חולקים את אותם שרתים, האם נתוני לקוחות חשופים, ומדוע הצוות אינו יכול להרים מכונה וירטואלית ייעודית ויקרה עבור כל קמפיין בנפרד.
הקצאת מכונה וירטואלית (VM) ייעודית לכל נכס דיגיטלי מונעת בעיות של "שכנים רועשים" (noisy neighbors), אך מכלה במהירות את תקציב התפעול. פריסות Docker סטנדרטיות פותרות את בעיית העלויות על ידי הרצת אתרים מרובים על גבי קרנל של מערכת הפעלה יחידה, אך תצורות ברירת המחדל משאירות פערי בידוד מסוכנים. אם אפליקציה של דייר אחד נתקלת בסקריפט שיצא משליטה או בפריצת אבטחה, כל אפליקציה אחרת המאוחסנת על אותו מארח (Host) נמצאת בסיכון.
השתמשו בתוכנית טכנית זו שלב אחר שלב כדי להגדיר בידוד Multi-Tenant קפדני ב-Docker. יישמו את חמשת השלבים התפעוליים הללו כדי להגן על יציבות המערכת, לבודד נתוני דיירים ולתרגם החלטות תשתית טכניות לערך עסקי ברור עבור ההנהלה.
1. אכיפת מכסות משאבים קשיחות באמצעות Control Groups
הגדירו מגבלות מעבד, זיכרון ו-I/O של דיסק באופן מפורש על כל קונטיינר באופן מיידי. כאשר מספר דיירים חולקים מארח משותף, קונטיינרים ללא הגבלות מתחרים על משאבי המערכת. שאילתת מסד נתונים שיצאה משליטה או קמפיין עתיר תנועה עלולים לכלות את כל מאגר הזיכרון של השרת, מה שיגרום למנגנון ה-Out-Of-Memory (OOM) killer של Linux להפסיק תהליכי מערכת שרירותיים.
מנגנון ה-Control groups (cgroups) של Linux שולט בכמות משאבי המחשוב שכל קונטיינר רשאי לצרוך. החילו את הגבולות הללו ישירות בהגדרות הפריסה שלכם:
services:
tenant_app:
image: nginx:alpine
deploy:
resources:
limits:
cpus: '0.75'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
- מגבלות זיכרון (
limits.memory): קובעות תקרה קשיחה. אם הקונטיינר חורג מ-512 מגה-בייט, הקרנל יפסיק תהליכים בתוך אותו קונטיינר מבלי לפגוע בדיירים שכנים. - הקצאות זיכרון שמורות (
reservations.memory): מבטיחות הקצאת זיכרון בסיסית כך שאפליקציות בעלות תנועה נמוכה יישארו מהירות ותגובתיות. - מגבלות מעבד (
limits.cpus): מגבילות את הקונטיינר לחלק מרבי מליבות המעבד הזמינות, ובכך מונעות הרעבת מעבד על ידי דייר בודד.
כאשר אתם מסבירים ארכיטקטורה זו להנהלה, הציגו את ה-cgroups כמעין מונים דיגיטליים נפרדים. כשם שדיירים בבניין משרדים משלמים על צריכת החשמל האישית שלהם במקום להעמיס יתר על המידה על המפסק הראשי, כך cgroups מבטיחים שדף נחיתה עתיר תנועה לעולם לא יפיל פורטל לידים של לקוח אחר. להעמקה בשיקולי הארכיטקטורה, עיינו במדריך שלנו בנושא תכנון ארכיטקטורת Multi-Tenant.
2. פילוח תהליכי דיירים באמצעות Namespaces ומשתמשים שאינם Root
לעולם אל תריצו תהליכי קונטיינר תחת משתמש ברירת המחדל root. בסביבות קונטיינרים סטנדרטיות של Linux, משתמש root בתוך קונטיינר תואם ל-root בקרנל של השרת המארח, אלא אם הוגדר מיפוי מחדש. אם תוקף פורץ לאפליקציית ווב הרצה כ-root, הוא מקבל הרשאות מוגברות על גבי המארח המשותף כולו.
אכפו בידוד תהליכים באמצעות user namespaces והרצה מפורשת תחת משתמשים ללא הרשאות root:
- הגדירו משתמשי זמן ריצה ללא הרשאות יתר: צרו משתמשי שירות ייעודיים ובעלי הרשאות נמוכות בקובצי ה-Dockerfile שלכם.
FROM php:8.2-fpm-alpine RUN addgroup -g 10001 tenantgroup && \ adduser -u 10001 -D -G tenantgroup tenantuser USER tenantuser - הפעילו User Namespaces (userns-remap): הגדירו את ה-Docker daemon (
/etc/docker/daemon.json) כך שימפה מזהי משתמשים של קונטיינרים לטווח מזהים נטול הרשאות במארח.{ "userns-remap": "default" }
מנגנון ה-Namespaces של Linux מחלק את נראות המערכת. ה-Process ID (PID) namespace מבטיח שדייר א' לא יוכל לצפות, לשלוח אותות או לסיים תהליכים השייכים לדייר ב'. ה-Mount (MNT) namespace מעניק לכל דייר תצוגה מבודדת של מערכת הקבצים, בעוד ש-IPC namespaces חוסמים תקשורת בין-תהליכית בלתי מורשית.
מיפוי מחדש של user namespaces מנטרל וקטורי בריחה מקונטיינרים (container escape): תהליך המזהה את עצמו כ-root (UID 0) בתוך הקונטיינר שלו ממופה למזהה חסר הרשאות (כגון UID 165536) במכונה המארחת. אם מתקפה עוקפת את גבולות הקונטיינר, התוקף ינחת במעטפת (shell) ללא הרשאות שלא תוכל לשנות הגדרות מארח או לגשת לספריות של דיירים שכנים.
3. הסרת הרשאות קרנל ואכיפת מערכות קבצים לקריאה בלבד
הסירו הרשאות Linux capabilities מיותרות והגדירו את מערכת קבצי השורש (root) של הקונטיינר כבלתי ניתנת לשינוי בעת העלייה. סביבות זמן ריצה סטנדרטיות של קונטיינרים מעניקות כברירת מחדל כעשרות יכולות קרנל שונות, שרובן המכריע אינו נחוץ לאפליקציות ווב. יכולות עודפות מספקות לתוקפים כלים לשינוי ניתוב רשת, עריכת שעון המערכת או עקיפת בקרות גישה לקבצים.
נעלו את קונטיינרי זמן הריצה על ידי ביטול כל יכולות ברירת המחדל והחזרה רק של דגלים תפעוליים חיוניים:
services:
tenant_web:
image: custom-nginx:latest
read_only: true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
- seccomp=default.json
tmpfs:
- /tmp:rw,noexec,nosuid,size=64m
- /var/run:rw,noexec,nosuid,size=16m
cap_drop: - ALL: מסיר כל יכולת קרנל מתהליך הקונטיינר.cap_add: - NET_BIND_SERVICE: מתיר במפורש האזנה לפורטים מורשים (כגון 80 ו-443) תוך חסימת מניפולציות ישירות על שקעי רשת (raw network sockets).read_only: true: מגדיר את כל מערכת קבצי השורש של הקונטיינר לקריאה בלבד (Read-only). תוקפים אינם יכולים להוריד קבצים בינאריים זדוניים, לערוך סקריפטים של PHP או לשנות קובצי קונפיגורציה של שרת האינטרנט.tmpfs: מקצה ספריות זמניות בזיכרון עבור קבצים נחוצים (כמו/tmp) תוך חסימת הרצת קבצים בינאריים (noexec) והעלאת הרשאות (nosuid).
השתמשו במסנני מצב מחשוב מאובטח (seccomp) ובמודולי אבטחה כגון AppArmor או SELinux כדי לנטר ולהגביל קריאות מערכת (system calls) לקרנל המשותף. אם הצוות שלכם מנהל בניית אפליקציות ווב מותאמות אישית, עקבו אחר השלבים המובנים שלנו עבור הקשחת קונטיינרים של Docker לאורך צינורות הפריסה שלכם.
4. הפרדת רשתות בין סביבות דיירים
בטלו את רשת ה-bridge של ברירת המחדל והגדירו רשתות bridge ייעודיות ומבודדות ברמת התוכנה עבור הסביבה של כל דייר. כברירת מחדל, קונטיינרים הנמצאים על רשת ה-bridge הסטנדרטית של Docker יכולים לגלות זה את זה ולתקשר באמצעות כתובות IP פנימיות. פגיעות במיקרו-שירות שיווקי של דייר אחד מאפשרת תנועה רוחבית (lateral movement) לכל מסד נתונים ואפליקציה פנימית אחרת באותו מארח.
בודדו את תעבורת הדיירים לחלוטין על ידי הגדרת גשרי רשת (network bridges) עצמאיים לכל דייר:
networks:
tenant_alpha_net:
driver: bridge
internal: true
tenant_beta_net:
driver: bridge
internal: true
public_gateway_net:
driver: bridge
services:
alpha_app:
image: tenant_a_app:latest
networks:
- tenant_alpha_net
- public_gateway_net
alpha_db:
image: mariadb:10.11
networks:
- tenant_alpha_net
beta_app:
image: tenant_b_app:latest
networks:
- tenant_beta_net
- public_gateway_net
beta_db:
image: mariadb:10.11
networks:
- tenant_beta_net
- בידוד דיירים:
alpha_appו-alpha_dbמתקשרים אך ורק דרךtenant_alpha_net. האפליקציהbeta_appאינה יכולה לגשת ל-alpha_db, גם אם תוקף סורק את תת-הרשת הפנימית. - דגל Internal (
internal: true): מונע מרשתות מסדי הנתונים לנתב תעבורה ישירות לאינטרנט החיצוני, ומגביל את הגישה הנכנסת והיוצאת לקונטיינרי האפליקציה בלבד. - שער Reverse Proxy: רק פרוקסי הכניסה (ingress proxy) מחובר לרשת
public_gateway_netכדי לנתב בקשות HTTP/HTTPS נכנסות לקונטיינר הדייר המתאים לפי שם המארח (hostname).
לסביבות מתקדמות יותר, שקלו שימוש במצבי Enhanced Container Isolation (ECI) של Docker או בסביבות זמן ריצה כגון Sysbox, האוכפות אוטומטית גבולות user namespaces מחמירים יותר ומערכות קבצים וירטואליות של /proc ו-/sys ללא צורך בסקריפטים ידניים מורכבים ברמת הרשת.
5. יצירת מטריצת החלטה אובייקטיבית עבור Multi-Tenancy
דחו את ההנחה שכל הנכסים הדיגיטליים דורשים מכונות וירטואליות ייעודיות. מנהלי שיווק מניחים לעיתים קרובות שבידוד ברמת החומרה באמצעות VM הוא מודל האבטחה הלגיטימי היחיד. בפועל, הקצאת מכונות וירטואליות ייעודיות עבור דפי נחיתה קלי משקל או אתרי קמפיין קצרי מועד מייצרת ניפוח עלויות משמעותי ותקורה תפעולית גבוהה, מבלי לשפר מהותית את אבטחת האפליקציה.
השתמשו במטריצת ההשוואה הבאה כדי להעריך את דרישות עומסי העבודה ולהציג אסטרטגיית פריסה רציונלית למקבלי ההחלטות:
| רמת בידוד | טכנולוגיית תשתית | גבול אבטחה | תקורה במשאבים | תרחיש שימוש מומלץ |
|---|---|---|---|---|
| קונטיינרים משותפים (Shared Stack) | Namespaces ו-Cgroups במערכת הפעלה אחת | בידוד לוגי ברמת מערכת ההפעלה | נמוכה מאוד | דפי נחיתה בעלי תנועה גבוהה, סביבות בדיקה (staging) פנימיות, אתרי קמפיין זמניים |
| קונטיינרים מוקשחים (ECI / Sysbox) | User namespaces, AppArmor, קובצי שורש לקריאה בלבד | רמה מתקדמת של מערכת הפעלה ווירטואליזציה | נמוכה | אחסון בסוכנויות עבור לקוחות מרובים, פורטלים מוגני אימות, טופסי שיווק רגישים |
| מכונות וירטואליות ייעודיות (VMs) | וירטואליזציית חומרה (Hypervisor) | הפרדה קשיחה ברמת החומרה/קרנל | גבוהה | סליקת תשלומים, נתונים תחת רגולציית HIPAA/PCI, הרצת קוד צד-שלישי לא מאומת |
| היברידי (קונטיינרים בתוך VMs ייעודיים) | קונטיינרים מוקשחים בתוך מכונות וירטואליות לכל דייר | גבולות חומרה ומערכת הפעלה מרובי שכבות | בינונית עד גבוהה | לקוחות אנטרפרייז מובילים הדורשים עמידה קפדנית בתנאי חוזה ייעודיים |
בחנו כל פרויקט מול קריטריונים ברורים לפני הקצאת תקציב תשתית:
- רגישות הנתונים: האם הפרויקט שומר מידע הכפוף לרגולציה (כגון רשומות כרטיסי אשראי או מידע רפואי)? אם כן, פרסו על גבי VM ייעודי.
- מקור הקוד: האם אתם פורסים קוד סטנדרטי שעבר ביקורת של הצוות, או מאפשרים תוספי צד שלישי שלא נבדקו? קוד סטנדרטי מתאים לקונטיינרים מוקשחים; קוד צד שלישי לא בדוק דורש בידוד מלא ברמת ה-Hypervisor.
- תקציב ואורך חיים: עבור דפי נחיתה עונתיים ואתרי חברה מרכזיים, ארכיטקטורת קונטיינרים מוקשחת מרובת דיירים מספקת יחס ביצועים לעלות אופטימלי.
כאשר אתם מציגים תוכניות תשתית להנהלה, היעזרו במדריך שלנו בנושא הערכה מתי לקוחות זקוקים למכונות וירטואליות ייעודיות כדי לגבות את ההמלצות שלכם בטיעונים מובנים לפי רמות.
סיכום: תרגום בקרות אבטחה לערך עסקי ו-ROI
אבטחת סביבת Docker מרובת דיירים אינה דורשת תקציב ענן של ארגוני ענק. היא דורשת יישום קפדני וממושמע של בקרות מערכת ההפעלה.
כאשר אתם סוקרים את מצב התשתית מול ההנהלה, מסגרו את ההגדרות הטכניות הללו סביב שלושה מדדים עסקיים מרכזיים:
- חיסכון בעלויות: קונטיינרים מרובי דיירים מאפשרים לצוות לארח עשרות אתרי שיווק בשבריר ממשאבי המחשוב הנדרשים עבור מכונות וירטואליות נפרדות.
- הגנה על זמינות השירות (Uptime): מנגנוני cgroups מבטיחים שעליות פתאומיות בתנועה בקמפיין עונתי לא יפגעו בביצועים של אתרי המותג המרכזיים.
- צמצום רדיוס הפגיעה (Blast Radius): מערכות קבצים לקריאה בלבד, ביטול הרשאות מיותרות וגשרי רשת מבודדים מבטיחים שחדירה לאתר בודד לא תאפשר גישה למסדי נתונים של לקוחות שכנים או לשליטה בשרת המארח.
יישמו כללי אבטחה אלה באופן שיטתי בכל תבניות הקונטיינרים שלכם. כך תספקו תשתית עתירת ביצועים וחסכונית בעלויות, העונה הן על תקני אבטחת המידע ההנדסיים והן על מגבלות התקציב של ההנהלה.

