סקירה כללית של מדיניות ההרשאות

בניגוד לאפליקציה מונוליתית שעשויה לפעול במקום אחד, אפליקציות של מיקרו-שירותים שמפוזרות באופן גלובלי מבצעות קריאות מעבר לגבולות הרשת. המשמעות היא שיש יותר נקודות כניסה לאפליקציות שלכם, ויותר הזדמנויות למתקפות זדוניות. בנוסף, לקבוצות Pod ב-Kubernetes יש כתובות IP זמניות, ולכן כללי חומת אש מסורתיים שמבוססים על כתובות IP לא מספיקים כדי לאבטח את הגישה בין עומסי עבודה. בארכיטקטורת מיקרו-שירותים, נדרשת גישה חדשה לאבטחה. ‫Cloud Service Mesh מתבסס על תכונות אבטחה כמו חשבונות שירות של Kubernetes ומדיניות אבטחה של Istio, ומספק עוד יכולות שיעזרו לכם לאבטח את האפליקציות.

בדף הזה מופיעה סקירה כללית על AuthorizationPolicyמשאב בהתאמה אישית (CR) לאופרטורים של אפליקציות. כללי מדיניות של הרשאות מאפשרים להפעיל בקרת גישה בעומסי עבודה בשכבת האפליקציה (L7) ובשכבת התעבורה (L3/4). אתם מגדירים מדיניות הרשאות כדי לציין הרשאות – מה מותר לשירות או למשתמש לעשות?

מדיניות הרשאות

כברירת מחדל, בקשות בין שירותים ברשת (וגם בין משתמשי קצה לשירותים) מותרות. משתמשים ב-AuthorizationPolicy CR כדי להגדיר מדיניות מפורטת לעומסי העבודה. אחרי שמחילים את מדיניות ההרשאות, Cloud Service Mesh מפיץ אותה ל-sidecar proxies. כשבקשות מגיעות לעומס עבודה, שרת ה-proxy מסוג קובץ עזר חיצוני בודק את מדיניות ההרשאות כדי לקבוע אם לאשר או לדחות את הבקשה.

במאמר תכונות נתמכות מפורטים השדות של AuthorizationPolicy CR שנתמכים בפלטפורמה.

היקף המדיניות

אפשר להחיל מדיניות על כל Service mesh, על מרחב שמות או על עומס עבודה ספציפי.

  • כדי להחיל מדיניות על כל הרשת, מציינים את מרחב השמות הבסיסי, istio-system, בשדה metadata:namespace:

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "mesh-wide"
      namespace: istio-system
    spec:
    ...
    
  • כדי להחיל מדיניות על מרחב שמות, מציינים את מרחב השמות בשדה metadata:namespace:

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "currencyservice"
      namespace: currencyservice
    spec:
    ...
    
  • כדי להגביל מדיניות למאגר ספציפי של כוח עבודה, צריך לכלול את השדה selector.

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "frontend"
      namespace: demo
    spec:
      selector:
        matchLabels:
          app: frontend
       ...
    

מבנה בסיסי

מדיניות הרשאות כוללת את היקף המדיניות, action ורשימה של rules:

  • כפי שמתואר בקטע הקודם, היקף המדיניות יכול להיות כל הרשת, מרחב שמות או עומס עבודה ספציפי. אם כוללים אותו, השדה selector מציין את היעד של המדיניות.

  • השדה action מציין אם ALLOW או DENY את הבקשה. אם לא מציינים פעולה, ברירת המחדל היא ALLOW. כדי למנוע בלבול, מומלץ תמיד לציין את הפעולה. (מדיניות הרשאות תומכת גם בפעולות AUDIT ו-CUSTOM). הפעולה AUDIT נתמכת רק בחלק מהפלטפורמות. פרטים נוספים מופיעים במאמר בנושא תכונות נתמכות.)

  • התג rules מציין מתי להפעיל את הפעולה.

    • השדה from ב-rules מציין את המקורות של הבקשה.

    • השדה to ב-rules מציין את הפעולות של הבקשה.

    • בשדה when מציינים תנאים נוספים שצריכים להתקיים כדי שהכלל יחול.

בדוגמה הבאה:

  • המדיניות חלה על בקשות לשירות frontend במרחב השמות demo.

  • הבקשות מותרות כשהמחרוזת hello:world מופיעה בכותרת הבקשה, אחרת הבקשות נדחות.

apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "hello-world"
  namespace: demo
spec:
  selector:
    matchLabels:
      app: frontend
  action: ALLOW
  rules:
  - when:
    - key: request.headers[hello]
      values: ["world"]

בקרת גישה בפעולת בקשה

אפשר לשלוט בגישה לפעולות ספציפיות של בקשות, כמו שיטות HTTP או יציאות TCP, על ידי הוספת קטע to מתחת ל-rules. בדוגמה הבאה, מותרות רק שיטות ה-HTTP‏ GET ו-POST ל-currencyservice במרחב השמות demo.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: currencyservice
 namespace: demo
spec:
 selector:
   matchLabels:
     app: currencyservice
 action: ALLOW
 rules:
 - to:
   - operation:
       methods: ["GET", "POST"]

בקרת גישה על זהות מאומתת

בדוגמאות הקודמות, כללי המדיניות מאפשרים בקשות מעומסי עבודה לא מאומתים. אם הפעלתם STRICT פרוטוקול TLS הדדי (mTLS), תוכלו להגביל את הגישה על סמך הזהות של עומס העבודה או מרחב השמות שממנו נשלחת הבקשה בקטע source.

  • משתמשים בשדה principals או בשדה notPrincipal כדי לשלוט בגישה ברמת עומס העבודה.

  • משתמשים בשדה namespaces או בשדה notNamespaces כדי לשלוט בגישה ברמת מרחב השמות.

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

עומס העבודה שזוהה

בדוגמה הבאה, בקשות אל currencyservice מותרות רק מהשירות frontend. בקשות אל currencyservice מעומסי עבודה אחרים נדחות.

apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "currencyservice"
  namespace: demo
spec:
  selector:
    matchLabels:
      app: currencyservice
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["example-project-1234.svc.id.goog/ns/demo/sa/frontend-sa"]

כדי לציין חשבון שירות, הערך principals צריך להיות בפורמט הבא:

principals: ["PROJECT_ID.svc.id.goog/ns/NAMESPACE/sa/SERVICE_ACCOUNT_NAME"]

אם אתם משתמשים ב-Cloud Service Mesh בתוך האשכול עם Citadel CA, אז cluster.local הוא דומיין האמון. בכל מקרה אחר, PROJECT_ID.svc.id.googהוא דומיין האמון של הרשת.

מרחב שמות מזוהה

בדוגמה הבאה מוצגת מדיניות שדוחה בקשות אם המקור הוא לא מרחב השמות foo:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin-deny
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: DENY
 rules:
 - from:
   - source:
       notNamespaces: ["foo"]

התאמת ערכים

רוב השדות במדיניות הרשאות תומכים בכל סכימות ההתאמה הבאות:

  • התאמה מדויקת: התאמה מדויקת של מחרוזת.
  • התאמה לתו כללי לחיפוש באמצעות התו הכללי לחיפוש "*":
    • התאמה לקידומת: מחרוזת עם סיומת "*". לדוגמה, "test.example.*" תואם ל-"test.example.com" או ל-"test.example.com.cn".
    • התאמה לסיומת: מחרוזת שמתחילה ב-"*". לדוגמה, "*.example.com" תואם ל-"eng.example.com" או ל-"test.eng.example.com".
  • התאמה לפי נוכחות: כדי לציין ששדה חייב להיות נוכח ולא ריק, משתמשים בפורמט fieldname: ["*"]. זה שונה מהשארת שדה ללא ציון, שמשמעותה התאמה לכל דבר, כולל שדה ריק.

יש כמה מקרים חריגים. לדוגמה, השדות הבאים תומכים רק בהתאמה מדויקת:

  • השדה key בקטע when
  • החלק ipBlocks מתחת לחלק source
  • השדה ports בקטע to

מדיניות ההרשאה הבאה מאפשרת גישה לנתיבים עם הקידומת /test/* או הסיומת */info:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: tester
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        paths: ["/test/*", "*/info"]

התאמה להחרגה

כדי להתאים תנאים שליליים כמו notValues בשדה when,‏ notIpBlocks בשדה source, ‏ notPorts בשדה to, ‏ Cloud Service Mesh תומך בהתאמה של החרגות. בדוגמה הבאה נדרשת בקשה תקינה principals, שנגזרת מאימות JWT, אם נתיב הבקשה הוא לא /healthz. לכן, המדיניות מחריגה בקשות לנתיב /healthz מאימות JWT:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: disable-jwt-for-healthz
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        notPaths: ["/healthz"]
    from:
    - source:
        requestPrincipals: ["*"]

דחיית בקשות בטקסט לא מוצפן

ב-Cloud Service Mesh, ‏ mTLS אוטומטי מופעל כברירת מחדל. עם mTLS אוטומטי, קובץ עזר חיצוני בצד הלקוח מזהה באופן אוטומטי אם לשרת יש קובץ עזר חיצוני. ה-sidecar של הלקוח שולח mTLS לעומסי עבודה עם sidecar ושולח טקסט רגיל לעומסי עבודה בלי sidecar. כדי להשיג את רמת האבטחה הגבוהה ביותר, מומלץ להפעיל mTLS מחמיר.

אם אתם לא מצליחים להפעיל mTLS עם מצב STRICT עבור עומס עבודה או מרחב שמות, אתם יכולים:

  • ליצור מדיניות הרשאות כדי לאפשר באופן מפורש תעבורה עם namespaces לא ריק או principals לא ריק, או
  • דחיית תנועה עם namespaces או principals ריקים.

מכיוון שאפשר לחלץ את namespaces ו-principals רק באמצעות בקשת mTLS, המדיניות הזו דוחה בפועל כל תנועה לא מוצפנת.

המדיניות הבאה דוחה את הבקשה אם הישות המורשית בבקשה ריקה (כמו במקרה של בקשות בטקסט לא מוצפן). המדיניות מאפשרת בקשות אם החשבון הראשי לא ריק. הסימן ["*"] מציין התאמה לא ריקה, והשימוש בו עם notPrincipals מציין התאמה לחשבון משתמש ריק.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: require-mtls
  namespace: NAMESPACE
spec:
  action: DENY
  rules:
  - from:
    - source:
        notPrincipals: ["*"]

קדימות של מדיניות הרשאות

אפשר להגדיר מדיניות הרשאות נפרדת של ALLOW ושל DENY, אבל חשוב להבין את סדר העדיפויות של המדיניות ואת התנהגות ברירת המחדל כדי לוודא שהמדיניות פועלת כמו שרוצים. בתרשים הבא מתוארת דיאגרמת סדר העדיפות של המדיניות.

קדימות של מדיניות הרשאות

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

לא לאפשר כלום

בדוגמה הבאה מוצגת מדיניות ALLOW שלא תואמת לשום דבר. כברירת מחדל, אם אין מדיניות ALLOW אחרת, הבקשות תמיד נדחות.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-nothing
spec:
  action: ALLOW

מומלץ להתחיל עם מדיניות שלא מאפשרת גישה לשום דבר, ולהוסיף בהדרגה עוד מדיניות ALLOW כדי לפתוח גישה לעומס עבודה.

דחיית כל בקשות הגישה

בדוגמה הבאה מוצגת מדיניות DENY שתואמת לכל דבר. מכיוון שכללי המדיניות של DENY נבדקים לפני כללי המדיניות של ALLOW, כל הבקשות נדחות גם אם יש מדיניות של ALLOW שתואמת לבקשה.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
spec:
  action: DENY
  rules:
  - {}

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

אישור גישה לכל התמונות

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

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-all
spec:
  action: ALLOW
  rules:
  - {}

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

שיטות מומלצות

  1. יוצרים חשבון שירות של Kubernetes לכל שירות ומציינים את חשבון השירות בפריסה. לדוגמה:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: frontend-sa
      namespace: demo
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: frontend
      namespace:demo
    spec:
      selector:
        matchLabels:
          app: frontend
      template:
        metadata:
          labels:
            app: frontend
        spec:
          serviceAccountName: frontend-sa
        ...
    
  2. מתחילים עם מדיניות שחוסמת הכול ומוסיפים בהדרגה עוד מדיניות ALLOW כדי לפתוח גישה לעומסי עבודה נוספים.

  3. אם אתם משתמשים ב-JWT בשירות שלכם:

    1. יוצרים מדיניות DENY לחסימת בקשות לא מאומתות, למשל:

      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: requireJWT
        namespace: admin
      spec:
        action: DENY
        rules:
        -  from:
          - source:
              notRequestPrincipals: ["*"]
      
    2. החלת מדיניות שלא מאפשרת כלום.

    3. מגדירים מדיניות ALLOW לכל עומס עבודה. דוגמאות מופיעות במאמר אסימון JWT.

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

מידע נוסף על תכונות האבטחה של Cloud Service Mesh:

מידע נוסף על מדיניות הרשאות זמין במסמכי Istio: