בידוד עומסי עבודה באמצעות GKE Sandbox

אתם יכולים להגן על ליבת המארח של צומתי Google Kubernetes Engine‏ (GKE) מפני קונטיינרים שמריצים קוד לא מהימן או לא מוכר באמצעות GKE Sandbox. במאמר הזה מוסבר למומחי אבטחה איך להפעיל את GKE Sandbox, להריץ Pods בארגזי חול (sandbox) ולאמת את הבידוד.

אתם כבר אמורים להכיר את GKE Sandbox.

סוגי ארגזי החול הזמינים

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

  • ‫gvisor: הטמעה מחדש של ממשק ה-API של ליבת Linux במרחב המשתמש, שלא דורשת הרשאות מורחבות. ליבת מרחב המשתמש מיירטת את רוב קריאות המערכת ומטפלת בהן בשם ליבת המארח, וכך מגבילה את הגישה הישירה לליבת המארח.
  • ‫microvm: מכונות וירטואליות קלות משקל שמוטמעות במכונה הווירטואלית המארחת באמצעות nested virtualization. כל Pod בצומת פועל במכונה וירטואלית נפרדת עם ליבת אורח משלו. מכיוון שהקוד פועל במכונה וירטואלית ייעודית, סוג ארגז החול הזה מספק בידוד חזק יותר מארגזי חול של gVisor.

במאמר מידע על GKE Sandbox מוסבר איך פועל כל סוג של ארגז חול ומתי כדאי להשתמש בסוג מסוים.

מגבלות

יש מגבלות שונות על GKE Sandbox ועל טכנולוגיות ספציפיות של ארגז חול, כמו תמיכה ב-GPU וב-TPU או תמיכה בתכונות ספציפיות של Linux ו-Kubernetes. מידע נוסף מופיע בקטע מגבלות.

לפני שמתחילים

לפני שמתחילים, חשוב לוודא שביצעתם את המשימות הבאות:

  • מפעילים את ממשק ה-API של Google Kubernetes Engine.
  • הפעלת Google Kubernetes Engine API
  • כדי להשתמש ב-Google Cloud CLI למשימה הזו, מתקינים ואז מאתחלים את ה-CLI של gcloud. אם התקנתם בעבר את ה-CLI של gcloud, מריצים את הפקודה gcloud components update כדי לקבל את הגרסה העדכנית. יכול להיות שגרסאות קודמות של ה-CLI של gcloud לא יתמכו בהרצת הפקודות שמופיעות במסמך הזה.

בחירת סוג ארגז חול לצמתים שנוצרים אוטומטית

אתם יכולים להשתמש ב-ComputeClasses עם מצב Autopilot או עם יצירה אוטומטית של מאגר צמתים כדי להפעיל את GKE Sandbox בצמתים שנוצרו על ידי GKE. באשכולות Autopilot, ‏ gVisor נתמך כברירת מחדל, כך שאפשר להשמיט את הגדרת הסביבת ארגז חול מ-ComputeClass.

כדי להגדיר את GKE Sandbox לצמתים שנוצרים אוטומטית, מבצעים את השלבים הבאים:

  1. חיבור לאשכול קיים במצב Autopilot או סטנדרטי:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=CONTROL_PLANE_LOCATION
    

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫CLUSTER_NAME: השם של האשכול.
    • ‫CONTROL_PLANE_LOCATION: האזור או האזור הזמין של מישור הבקרה של האשכול.
  2. שומרים אחד ממניפסטים של ComputeClass הבאים, בהתאם לטכנולוגיית ארגז החול שרוצים:

    • ‫gVisor:

      apiVersion: cloud.google.com/v1
      kind: ComputeClass
      metadata:
        name: sandbox-gvisor-class
      spec:
        priorities:
        - machineFamily: n4
        - machineFamily: c4
        nodePoolConfig:
          sandbox:
            type: gvisor
        nodePoolAutoCreation:
          enabled: true
        whenUnsatisfiable: DoNotScaleUp
      
    • microVM:

      apiVersion: cloud.google.com/v1
      kind: ComputeClass
      metadata:
        name: sandbox-microvm-class
      spec:
        priorities:
        - machineFamily: n4
        - machineFamily: c4
        nodePoolConfig:
          sandbox:
            type: microvm
        priorityDefaults:
          enableNestedVirtualization: true
        nodePoolAutoCreation:
          enabled: true
        whenUnsatisfiable: DoNotScaleUp
      

      ה-ComputeClass לארגזי חול של מכונות מיקרו וירטואליות מאפשר וירטואליזציה מקוננת באמצעות השדה enableNestedVirtualization. השדה הזה נדרש לארגזי חול של microVM. כדי להשתמש בשדה הזה, האשכול צריך להיות בגרסה 1.37.0-gke.4713000 ואילך.

    במניפסטים לדוגמה האלה נעשה שימוש בשדה nodePoolAutoCreation כדי להפעיל יצירה אוטומטית של מאגרי צמתים. אפשר גם לציין את הגדרות הסביבת ארגז חול ב-ComputeClass שמשתמש בשדה autopilot כדי להריץ את ה-Pods במצב אוטומטי. אם אתם משתמשים באשכולות Autopilot, ‏ GKE מתעלם מהשדות nodePoolAutoCreation ו-autopilot.

  3. יוצרים את ComputeClass:

    kubectl apply -f PATH_TO_COMPUTE_CLASS_MANIFEST
    

    מחליפים את PATH_TO_COMPUTE_CLASS_MANIFEST בנתיב למניפסט של ComputeClass.

כדי לבחור את ComputeClass הזה ולבקש סביבת Sandbox, אפשר לעיין במאמר בנושא בקשת סביבת Sandbox ל-Pod.

בחירת סוג ארגז חול כשיוצרים מאגרי צמתים

אפשר להפעיל את GKE Sandbox באופן ידני כשיוצרים מאגר צמתים חדש באשכול רגיל. ההגבלות הבאות חלות כשמפעילים את GKE Sandbox באופן ידני:

  • כדי להפעיל את GKE Sandbox במהלך יצירת אשכול Standard, צריך להגדיר לפחות מאגר צמתים נוסף אחד. בריכת הצמתים הנוספת נדרשת כי GKE צריך לפחות בריכת צמתים אחת באשכול שלא משתמשת ב-GKE Sandbox כדי להריץ עומסי עבודה של מערכת שמנוהלים על ידי GKE. אם משתמשים ב-CLI של gcloud כדי ליצור את האשכול, צריך ליצור את האשכול ואז ליצור מאגר צמתים שמשתמש ב-GKE Sandbox.
  • כדי לבחור את סוג ארגז החול של microVM, צריך להשתמש ב-CLI של gcloud או ב-GKE API. במסוףCloud de Confiance אי אפשר לבחור את סוג ארגז החול microVM.

הפעלת סוג ארגז החול gVisor

כדי להפעיל באופן ידני ארגזי חול של gVisor כשיוצרים מאגר צמתים חדש, בוחרים באחת מהאפשרויות הבאות:

המסוף

  1. נכנסים לדף Kubernetes clusters במסוף Cloud de Confiance .

    מעבר אל Kubernetes clusters

  2. לוחצים על השם של האשכול שרוצים לשנות. נפתח הדף Cluster details.

  3. לוחצים על הכרטיסייה Nodes (צמתים).

  4. בקטע מאגרי צמתים, לוחצים על הוספת מאגר צמתים מנוהל על ידי המשתמש. נפתח הדף Add a node pool (הוספת מאגר צמתים).

  5. בתפריט הניווט, לוחצים על Nodes ומגדירים את ההגדרות הבאות:

    1. בתפריט הנפתח Image type, בוחרים באפשרות Container-Optimized OS with Containerd (cos_containerd).
    2. בקטע Machine configuration, בוחרים סדרת מכונות וסוג מכונה לצמתים.
    3. אופציונלי: בוחרים סוג GPU נתמך או סוג TPU נתמך.
  6. בתפריט הניווט, לוחצים על אבטחה. ייפתח הדף אבטחת הצומת.

  7. מסמנים את התיבה הפעלת ארגז חול (sandbox) עם gVisor.

  8. כדי ליצור את מאגר הצמתים, לוחצים על Create (יצירה).

gcloud

כדי ליצור מאגר צמתים שמשתמש ב-gVisor לארגזי חול, מריצים את הפקודה הבאה:

gcloud container node-pools create NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --sandbox=type=gvisor

מחליפים את מה שכתוב בשדות הבאים:

  • ‫NODE_POOL_NAME: שם למאגר הצמתים.
  • ‫CLUSTER_NAME: השם של האשכול.
  • ‫CONTROL_PLANE_LOCATION: האזור או האזור הזמין של מישור הבקרה של האשכול.

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

הפעלת סוג ארגז החול microVM

אפשר להפעיל את סוג ארגז החול microVM כשיוצרים מאגר צמתים באמצעות ה-CLI של gcloud או GKE API. ב Cloud de Confiance מסוף אין תמיכה בהפעלת סוג ארגז החול של microVM. כדי ליצור מאגר צמתים שמשתמש בארגזי חול של מכונות מיקרו-וירטואליות, מריצים את הפקודה הבאה:

gcloud container node-pools create NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --sandbox=type=microvm \
    --enable-nested-virtualization \
    --machine-type=MACHINE_TYPE

מחליפים את מה שכתוב בשדות הבאים:

  • ‫NODE_POOL_NAME: שם למאגר הצמתים.
  • ‫CLUSTER_NAME: שם האשכול.
  • ‫CONTROL_PLANE_LOCATION: האזור או האזור של מישור הבקרה של האשכול.
  • ‫MACHINE_TYPE: סוג המכונה של הצמתים. הערך הזה חייב להיות סוג מכונה שתומך בווירטואליזציה בתצורה מקוננת. מידע נוסף זמין בשורה Nested virtualization בטבלת ההשוואה בין סדרות המכונות.

הפעלת מעקב ורישום ביומן

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

השירותים האלה מופעלים כברירת מחדל בכל אשכולות GKE החדשים.

בקשת סביבת ארגז חול ל-Pod

כדי להריץ Pod ספציפי בארגז חול, אפשר לציין את RuntimeClass של gvisor או microvm במפרט של ה-Pod. ‫GKE מתזמן את ה-Pod בצמתים שמשתמשים בסוג ארגז החול שצוין. כדי לבחור סוג של ארגז חול במפרט של Pod, פועלים לפי השלבים הבאים:

  1. שומרים את אחד ממניפסטים הפריסה לדוגמה הבאים, בהתאם לאופן שבו הפעלתם את GKE Sandbox באמצעות ComputeClasses או מאגרי צמתים שנוצרו באופן ידני:

    • ‫ComputeClasses:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: sandbox-pod
        labels:
          environment: sandbox
      spec:
        replicas: 2
        selector:
          matchLabels:
            environment: sandbox
        template:
          metadata:
            labels:
              environment: sandbox
          spec:
            nodeSelector:
              cloud.google.com/compute-class: COMPUTECLASS_NAME
            runtimeClassName: SANDBOX_TYPE
            
            containers:
            - name: nginx
              image: nginx
      

      מחליפים את מה שכתוב בשדות הבאים:

      • ‫COMPUTECLASS_NAME: השם של ComputeClass שיצרתם, כמו שמתואר במאמר בחירת סוג ארגז חול לצמתים שנוצרים אוטומטית.

      • ‫SANDBOX_TYPE: סוג ארגז החול שבו רוצים להשתמש עבור ה-Pods. יש תמיכה בערכים הבאים:

        • gvisor
        • microvm

        סוג ארגז החול שאתם מציינים צריך להיות זהה לסוג ארגז החול שמאפשרת ComputeClass שנבחרה.

    • מאגרי צמתים שנוצרו באופן ידני:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: httpd
        labels:
          app: httpd
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: httpd
        template:
          metadata:
            labels:
              app: httpd
          spec:
            runtimeClassName: SANDBOX_TYPE
            containers:
            - name: httpd
              image: httpd
      

      מחליפים את SANDBOX_TYPE בסוג של ארגז החול. הערכים הבאים נתמכים:

      • gvisor
      • microvm

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

  2. יוצרים את הפריסה:

    kubectl apply -f PATH_TO_DEPLOYMENT_MANIFEST
    

    מחליפים את PATH_TO_DEPLOYMENT_MANIFEST בנתיב למניפסט הפריסה.

  3. מוודאים שה-Pods נוצרו:

    kubectl get pods
    

    הפלט אמור להיראות כך:

    NAME                    READY   STATUS    RESTARTS   AGE
    httpd-db5899bc9-dk7lk   1/1     Running   0          24s
    

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

הפעלת Pod רגיל לצד Pods בארגז חול

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

אחרי שמפעילים את GKE Sandbox במאגר צמתים, אפשר להריץ צמתים מהימנים בלי להשתמש בארגז חול, באמצעות taints ו-tolerations של צמתים. ה-Pods האלה נקראים 'Pods רגילים' כדי להבדיל ביניהם לבין Pods בתוך ארגז חול.

ל-Pods רגילים, בדיוק כמו ל-Pods בסביבת ארגז חול, אין גישה לCloud de Confiance שירותים אחרים או למטא-נתונים של האשכול. המניעה הזו היא חלק מההגדרות של הצומת. אם הפודים הרגילים או הפודים בארגז החול צריכים גישה לשירותיCloud de Confiance , השתמשו באיחוד זהויות של עומסי עבודה ל-GKE.

‫GKE Sandbox מוסיף את התווית וה-taint הבאים לצמתים שיכולים להריץ Pods בארגז חול:

  • התווית של צומת sandbox.gke.io/runtime: SANDBOX_TYPE.
  • הדחייה (taint) של הצומת sandbox.gke.io/runtime=SANDBOX_TYPE:NoSchedule. אפשר לתזמן צמתים רק ל-Pods שיש להם התאמה לסבילות.

אם משתמשים בשדה RuntimeClass כדי להריץ Pod בסביבת ארגז חול, ‏ GKE מחיל אוטומטית זיקה של צומת וטולרנטיות על ה-Pod. כדי להריץ Pod רגיל בצומת שמשתמש ב-GKE Sandbox, צריך להחיל באופן ידני את הסלקטורים הבאים על מפרט ה-Pod:

  • כדי לאפשר ל-Pod לפעול בצמתים שמשתמשים ב-GKE Sandbox כשצריך, מוסיפים רק את ה-טולרנטיות ל-דחייה (taint) של הצומת.
  • כדי להריץ את ה-Pod רק בצמתים שמשתמשים ב-GKE Sandbox, מוסיפים בורר צמתים וטולרנטיות ל-node taint.

בשלבים הבאים מוסבר איך להריץ Pod רגיל בצומת שמשתמש ב-GKE Sandbox:

  1. שומרים את מניפסט הפריסה הבא בתור httpd-regular.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpd-regular
      labels:
        app: httpd-regular
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: httpd-regular
      template:
        metadata:
          labels:
            app: httpd-regular
        spec:
          containers:
          - name: httpd-regular
            image: httpd
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: sandbox.gke.io/runtime
                    operator: In
                    values:
                    - SANDBOX_TYPE
          tolerations:
            - effect: NoSchedule
              key: sandbox.gke.io/runtime
              operator: Equal
              value: SANDBOX_TYPE
    

    מחליפים את SANDBOX_TYPE בסוג של ארגז החול, כמו gvisor או microvm.

  2. יוצרים את הפריסה:

    kubectl apply -f httpd-regular.yaml
    

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

  3. מוודאים שה-Pod לא נמצא בסביבת ארגז חול:

    kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'
    

    הפלט אמור להיראות כך:

    httpd-db5899bc9-dk7lk: SANDBOX_TYPE
    httpd-regular-5bf87996c6-cfmmd:
    

    ל-Pod‏ httpd-regular אין ערך של RuntimeClass, כלומר ה-Pod לא נמצא בארגז חול.

  4. מוודאים שה-Pod הרגיל פועל בצומת שמשתמש ב-GKE Sandbox:

    kubectl get pod -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.nodeName}\n{end}'
    

    הפלט אמור להיראות כך:

    httpd-db5899bc9-dk7lk: gke-cluster-2-pool-1-75c8fc63-h373
    httpd-regular-5bf87996c6-cfmmd: gke-cluster-2-pool-1-75c8fc63-h373
    

    ה-Pod בארגז החול וה-Pod הרגיל נמצאים באותו צומת, מה שמצביע על כך שה-Pod הרגיל פועל בצומת שמשתמש ב-GKE Sandbox.

אימות ההגדרות של ארגז החול

בקטעים הבאים מוסבר איך לוודא ש-Pod פועל בארגז חול ושה-Pod בארגז החול מבודד מליבת המארח. בקטעים האלה אנחנו מניחים שיצרתם את ה-Deployment לדוגמה בבקשת סביבת Sandbox ל-Pod.

איך מוודאים ש-Pod פועל בארגז חול

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

  • מקבלים את ה-RuntimeClass של כל Pod שפועל:

    kubectl get pods -l=app=httpd -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'
    

    הפלט אמור להיראות כך:

    httpd-db5899bc9-dk7lk: gvisor
    httpd-db5899bc9-ab3cd: gvisor
    

    אם הפלט הוא gvisor או microvm, ה-Pod פועל בארגז חול.

אימות הבידוד של ה-Pods בארגז חול מהמארח

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

  1. בארגזי חול של gVisor ושל מכונות וירטואליות מיקרו, בודקים אם גרסת הליבה שאליה יש ל-Pod גישה שונה מגרסת הליבה של צומת המארח:

    1. מקבלים את גרסת הליבה שלפוד יש גישה אליה:

      kubectl exec POD_NAME -- uname -r
      

      מחליפים את POD_NAME בשם של ה-Pod.

      הפלט אמור להיראות כך:

      4.19.0-gvisor
      
    2. כדי לקבל את גרסת הליבה בצומת המארח:

      kubectl get node NODE_NAME \
          -o jsonpath='{.status.nodeInfo.kernelVersion}'
      

      מחליפים את NODE_NAME בשם הצומת שבו פועל ה-Pod.

      הפלט אמור להיראות כך:

      6.12.94+
      

    גרסת הליבה של צומת המארח שונה מגרסת הליבה שאליה יש ל-Pod בסביבת ארגז חול גישה, כי ה-Pod רואה רק את ליבת מרחב המשתמשים של gVisor או את ליבת האורח של מכונות וירטואליות מיקרו.

  2. בארגזי חול של מכונות וירטואליות מיקרו, אפשר גם לבדוק אם המכשירים שיש ל-Pod גישה אליהם עוברים וירטואליזציה על ידי Cloud Hypervisor:

    kubectl exec POD_NAME -- cat /sys/class/dmi/id/product_name
    

    אם הפלט הוא cloud-hypervisor, ה-Pod נמצא בארגז חול של microVM.

השבתת GKE Sandbox

אי אפשר להשבית את GKE Sandbox באשכולות GKE Autopilot או במאגרי צמתים של GKE Standard. אם רוצים להפסיק להשתמש ב-GKE Sandbox, צריך למחוק את מאגר הצמתים.

המאמרים הבאים