בלוג

הגנה מפני בריחת קונטיינרים: מדריך מעשי לבידוד Docker לאירוח מרובה דיירים

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

סיכום

קונטיינרים של Docker חולקים את ליבת המערכת המארחת, מה שהופך את הבידוד לקריטי—במיוחד באירוח מרובה דיירים שבו בריחת קונטיינר אחת יכולה לפגוע בכל הדיירים. מפתחים רבים מניחים שקונטיינרים הם מכונות וירטואליות מבודדות לחלוטין, אך המציאות שונה. מאמר זה מסביר את תכונות ליבת לינוקס העומדות בבסיס בידוד Docker (מרחבי שמות, cgroups) ואת וקטורי התקיפה המאיימים עליהם. תלמד צעדים מעשיים לחיזוק הגדרות ה-Docker שלך: הגבלת הרשאות, שימוש בסביבת ריצה מאובטחת, סריקת תמונות ויישום פילוח רשת. על ידי מעקב אחר דוגמה מהעולם האמיתי של ספק אירוח WordPress מרובה דיירים, תראה כיצד ליישם הגנות אלו. אנו מכסים גם הסתייגויות כמו פשרות ביצועים ושימוש ב-seccomp/AppArmor. המטרה היא לתת לך אסטרטגיית בידוד חזקה שתמנע בריחות קונטיינרים ותשמור על בטיחות הדיירים שלך.

מבוא

אם אתה מפעיל פלטפורמת אירוח מרובה דיירים—בין אם זה אירוח WordPress משותף, יישום SaaS, או שירות סביבת פיתוח—בריחת קונטיינר היא תרחיש האימה. פגיעות בליבה או תצורה שגויה יכולות לאפשר לדייר אחד לפרוץ מתוך הקונטיינר שלו ולגשת לנתונים של דיירים אחרים או למערכת המארחת עצמה. הבידוד של Docker מסתמך על תכונות ליבת לינוקס כמו מרחבי שמות (namespaces) ו-cgroups, אך תצורות "מחוץ לקופסה" לרוב אינן מספיקות לאבטחה חזקה. מאמר זה ידריך אותך דרך וקטורי התקיפה ויספק צעדים מעשיים לנעילת קונטיינרי ה-Docker שלך, המומחשים באמצעות דוגמת WordPress מרובה דיירים מהעולם האמיתי. למבט רחב יותר על תזמור הפקה, עיין במדריך שלנו על תזמור יישומים מכולות מוכנים להפקה.

הבנת בידוד Docker

קונטיינרים של Docker משתמשים במרחבי שמות של לינוקס כדי לספק בידוד ברמת התהליך: מרחבי שמות PID מבודדים עצי תהליכים, מרחבי שמות רשת מפרידים ממשקי רשת, מרחבי שמות mount מבודדים מערכות קבצים, ומרחבי שמות משתמשים מאפשרים מיפוי של root הקונטיינר למשתמש מארח לא מורשה. קבוצות בקרה (cgroups) מגבילות שימוש במשאבים כמו CPU, זיכרון וקלט/פלט דיסק. תכונות אלו יחד יוצרות "ארגז חול" סביב כל קונטיינר. עם זאת, בניגוד למכונה וירטואלית שמריצה ליבה נפרדת, קונטיינרים חולקים את ליבת המערכת המארחת. זה אומר שפגיעות בליבה (למשל, CVE-2022-0492) ניתנת לניצול כדי לפרוץ מבידוד מרחב השמות של הקונטיינר. בנוסף, תצורות שגויות כמו הרצת קונטיינרים כ-root בתוך הקונטיינר, מתן כל היכולות לקונטיינר, או אי-הפלת יכולות לינוקס מיותרות יכולות להרחיב את משטח התקיפה.

וקטורי תקיפה

וקטורי תקיפה נפוצים כוללים:

  • ניצול ליבה: ניצול באג בליבת המערכת המארחת כדי להשיג גישה למארח.
  • קונטיינרים מורשים: הרצה עם --privileged מעניקה את כל היכולות ועוקפת את רוב הבידוד.
  • שימוש לרעה ביכולות: גם ללא מצב הרשאה מלא, קונטיינר עם יכולות מסוכנות כמו CAP_SYS_ADMIN או CAP_NET_ADMIN יכול למנט קבצים או לתמרן הגדרות רשת.
  • שיטות תמונה לא מאובטחות: שימוש בתמונות בסיס עם פגיעויות ידועות או הכללת כלים מיותרים כמו מקמפלים או מפרשי shell.
  • מרחבי שמות mount משותפים: מיפוי ספריות מארח לקונטיינרים יכול לאפשר בריחה אם אינם לקריאה בלבד.

צעדים מעשיים לאבטחה

1. הפעל קונטיינרים כמשתמש לא-root

כברירת מחדל, Docker מריץ קונטיינרים כ-root בתוך הקונטיינר. אם תוקף משיג root בתוך הקונטיינר, יש לו יותר מנוף. צור משתמש ב-Dockerfile שלך והשתמש בהוראת USER. כמו כן, הימנע משימוש בדגל --user ב-Docker Compose כדי למפות למשתמש מארח שרירותי אם אפשר.

2. הפל את כל היכולות והוסף רק את הנדרשות

יכולות לינוקס מפרקות הרשאות superuser ליחידות קטנות יותר. ב-Docker Compose, השתמש ב-cap_drop: ALL ואז cap_add רק את אלו הנדרשות (למשל, NET_BIND_SERVICE). הימנע מיכולות מסוכנות כמו SYS_ADMIN, NET_ADMIN, SYS_PTRACE.

3. השתמש במערכת קבצים root לקריאה בלבד

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

4. הפעל מיפוי מחדש של מרחב שמות משתמשים

מיפוי מחדש של מרחב שמות משתמשים ממפה את משתמש ה-root של הקונטיינר למשתמש מארח לא-root. זה מוסיף שכבת בידוד, מכיוון שאפילו אם root הקונטיינר פורץ החוצה, תהיה לו ההרשאות של המשתמש הממופה מחדש. הפעל אותו ב-/etc/docker/daemon.json עם "userns-remap": "default". שים לב שזה יכול לסבך הרשאות נפח. לפרטים נוספים, עיין בשליטה בבידוד Docker לאירוח ווב מאובטח ויעיל.

5. החל פרופילי Seccomp ו-AppArmor/AppArmor

Seccomp מגביל את קריאות המערכת שקונטיינר יכול לבצע. Docker מספק פרופיל seccomp ברירת מחדל שחוסם קריאות מערכת מסוכנות. אתה יכול גם ליצור פרופילים מותאמים אישית. באופן דומה, AppArmor (או SELinux) מספק בקרת גישה חובה. השתמש ב-AppArmor כדי להגביל את הקונטיינר שלך למערך מינימלי של פעולות מותרות. ניתן להגדיר את פרופיל האבטחה באמצעות security_opt ב-Docker Compose.

6. השתמש בתמונות בסיס מינימליות וסרוק אחר פגיעויות

בחר תמונות קטנות כמו Alpine או Distroless שיש להן משטח תקיפה קטן יותר. סרוק באופן קבוע תמונות עם כלים כמו Docker Scout, Trivy, או Clair. שלב סריקה בתהליך ה-CI/CD שלך כדי למנוע פריסה של תמונות פגיעות.

7. פילוח רשת עם רשתות גשר מותאמות אישית

צור רשתות גשר נפרדות לכל דייר או שכבת יישום. זה מגביל תעבורת מזרח-מערב. ב-Docker Compose, הגדר רשתות ובודד שירותים. השתמש ב-internal: true אם שירות אינו זקוק לגישה לאינטרנט יוצאת. כללי חומת אש במארח מגבילים עוד יותר תעבורה בין קונטיינרים.

8. הגבל משאבים עם Cgroups

הגדר מגבלות CPU וזיכרון ב-Docker Compose באמצעות deploy.resources.limits. זה מונע מקונטיינר שנפרץ להשיק התקפת מיצוי משאבים. בנוסף, הגדר kernel_memory ו-memory_reservation לשליטה מדויקת יותר.

דוגמה מהעולם האמיתי: אירוח WordPress מרובה דיירים עם Docker Compose

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

version: '3'
services:
  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - ./wp-content:/var/www/html/wp-content
  db:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_ROOT_PASSWORD: somewordpress
    volumes:
      - db_data:/var/lib/mysql
volumes:
  db_data:

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

כעת נחזק אותה:

version: '3'
services:
  wordpress:
    image: wordpress:latest
    user: www-data
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    read_only: true
    tmpfs:
      - /var/www/html/wp-content/plugins
    security_opt:
      - seccomp=seccomp-profile.json
      - apparmor=wordpress-profile
    networks:
      - frontend
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - wp-uploads:/var/www/html/wp-content/uploads
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M
  db:
    image: mysql:5.7
    user: mysql
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    networks:
      - backend
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_ROOT_PASSWORD: somewordpress
    volumes:
      - db_data:/var/lib/mysql
    deploy:
      resources:
        limits:
          cpus: '0.25'
          memory: 128M
networks:
  frontend:
    driver: bridge
    internal: false
  backend:
    driver: bridge
    internal: true
volumes:
  wp-uploads:
  db_data:

שיפורים עיקריים:

  • שני הקונטיינרים פועלים כמשתמשים לא-root (www-data ו-mysql).
  • כל היכולות הופלו, רק NET_BIND_SERVICE נוסף.
  • מערכת הקבצים של WordPress היא לקריאה בלבד למעט mount של tmpfs ונפח uploads.
  • פרופילי Seccomp ו-AppArmor מיושמים (תצטרך לספק פרופילים מותאמים אישית).
  • רשתות נפרדות מבודדות את ה-web מה-database, כאשר רשת ה-database פנימית.
  • מגבלות משאבים מונעות מיצוי משאבים.

לעוד מידע על חיזוק Docker ספציפי ל-WordPress, עיין בDocker עבור WordPress: מדוע קונטיינרים מבודדים משנים הכל.

הסתייגויות

  • מיפוי מחדש של מרחב שמות משתמשים: למרות שהוא חזק, הוא שובר מיפוי נפחים מכיוון ש-UID המארח הממופה מחדש אינו זהה ל-UID של הקונטיינר. ייתכן שתצטרך ליצור מראש ספריות עם ההרשאות הנכונות או להשתמש בנפחי Docker עם תמיכה במיפוי מחדש.
  • פרופילי Seccomp/AppArmor: פרופילים מותאמים אישית דורשים הבנה של דפוסי קריאות המערכת וגישת הקבצים של האפליקציה שלך. פרופילים מגבילים מדי עלולים לשבור פונקציונליות. בדוק ביסודיות.
  • ביצועים: שכבות אבטחה נוספות כמו seccomp ו-AppArmor בעלות תקורה מינימלית, אך מגבלות משאבים ומערכות קבצים לקריאה בלבד עשויות להשפיע על יישומים עתירי כתיבה.
  • מורכבות תזמור: בסביבה מרובת דיירים, ניהול קבצי Docker Compose פר-דייר יכול להפוך למסורבל. שקול להשתמש בכלי תזמור ברמה גבוהה יותר כמו Kubernetes, אך זה מציג שיקולי אבטחה משלו.

מסקנה

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

Sources (5)