כתיבה של תבנית אילוצים בהתאמה אישית

בדף הזה נסביר איך לכתוב תבנית אילוץ בהתאמה אישית ולהשתמש בה כדי להרחיב את Policy Controller אם לא מצאתם תבנית אילוץ מוכנה מראש שמתאימה לצרכים שלכם.

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

כללי המדיניות של Policy Controller מתוארים באמצעות OPA Constraint Framework ונכתבים ב-Rego. מדיניות יכולה להעריך כל שדה של אובייקט Kubernetes.

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

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

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

דוגמה לתבנית אילוצים

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

אם אתם משתמשים ב-סנכרון תצורות עם מאגר היררכי, מומלץ ליצור את האילוצים בספרייה cluster/.

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdenyname
spec:
  crd:
    spec:
      names:
        kind: K8sDenyName
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            invalidName:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sdenynames
        violation[{"msg": msg}] {
          input.review.object.metadata.name == input.parameters.invalidName
          msg := sprintf("The name %v is not allowed", [input.parameters.invalidName])
        }

מגבלה לדוגמה

הדוגמה הבאה היא אילוץ שאפשר להטמיע כדי לדחות את כל המשאבים שנקראים policy-violation:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyName
metadata:
  name: no-policy-violation
spec:
  parameters:
    invalidName: "policy-violation"

החלקים של תבנית אילוצים

תבניות של אילוצים מורכבות משני חלקים חשובים:

  • הסכימה של האילוץ שרוצים שהמשתמשים ייצרו. הסכימה של תבנית אילוצים מאוחסנת בשדה crd.

  • קוד המקור של Rego שמופעל כשמתבצעת הערכה של האילוץ. קוד המקור של Rego לתבנית מאוחסן בשדה targets.

סכימה (שדה crd)

שדה ה-CRD הוא תוכנית ליצירת Kubernetes Custom Resource Definition שמגדיר את משאב האילוץ עבור שרת ה-API של Kubernetes. צריך למלא רק את השדות הבאים.

שדה תיאור
spec.crd.spec.names.kind סוג האילוץ. כשממירים לאותיות קטנות, הערך בשדה הזה צריך להיות שווה ל-metadata.name.
spec.crd.spec.validation.openAPIV3Schema

הסכימה של השדה spec.parameters במשאב המגבלה (Policy Controller מגדיר אוטומטית את שאר הסכימה של המגבלה). היא פועלת לפי אותן מוסכמות כמו במשאב CRD רגיל.

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

קוד מקור של Rego (שדה targets)

בקטעים הבאים מפורט מידע נוסף על קוד המקור של Rego.

מיקום

קוד המקור של Rego מאוחסן בשדה spec.targets, כאשר targets הוא מערך של אובייקטים בפורמט הבא:

{"target": "admission.k8s.gatekeeper.sh","rego": REGO_SOURCE_CODE, "libs": LIST_OF_REGO_LIBRARIES}
  • target: מציין ל-Policy Controller את המערכת שאנחנו בודקים (במקרה הזה Kubernetes). מותרת רק רשומה אחת ב-targets.
  • rego: קוד המקור של האילוץ.
  • libs: רשימה אופציונלית של ספריות של קוד Rego שזמינות לתבנית האילוצים. הרשימה הזו נועדה להקל על השימוש בספריות משותפות, אבל היא לא נכללת במסגרת המסמך הזה.

קוד מקור

קוד המקור של Rego לאילוץ הקודם:

package k8sdenynames

violation[{"msg": msg}] {
   input.review.object.metadata.name == input.parameters.invalidName
   msg := sprintf("The name %v is not allowed", [input.parameters.invalidName])
}

שימו לב לנקודות הבאות:

  • השדה package k8sdenynames נדרש על ידי OPA (זמן הריצה של Rego). המערכת מתעלמת מהערך.
  • כלל Rego ש-Policy Controller מפעיל כדי לבדוק אם יש הפרות נקרא violation. אם יש התאמות לכלל הזה, סימן שהייתה הפרה של האילוץ.
  • הכלל violation כולל את החתימה violation[{"msg": "violation message for the user"}], כאשר הערך של "msg" הוא הודעת ההפרה שמוחזרת למשתמש.
  • הפרמטרים שמועברים לאילוץ זמינים תחת מילת המפתח input.parameters.
  • ה-request-under-test מאוחסן תחת מילת המפתח input.review.

מילת המפתח input.review כוללת את השדות הבאים.

שדה תיאור
uid המזהה הייחודי של הבקשה הספציפית הזו. המזהה לא זמין במהלך ביקורת.
kind

המידע על הסוג של object-under-test. הפורמט הוא:

  • kind: סוג המשאב
  • group: קבוצת המשאבים
  • version: גרסת המשאב
name שם המשאב יכול להיות שהשדה יהיה ריק אם המשתמש מסתמך על שרת ה-API כדי ליצור את השם בבקשת CREATE.
namespace מרחב השמות של המשאב (לא מסופק למשאבים בהיקף אשכול).
operation הפעולה המבוקשת (לדוגמה, CREATE או UPDATE). היא לא זמינה במהלך ביקורת.
userInfo

המידע של המשתמש ששלח את הבקשה. המידע הזה לא זמין במהלך ביקורת. הפורמט הוא:

  • username: המשתמש ששולח את הבקשה
  • uid: מזהה המשתמש
  • groups: רשימה של קבוצות שהמשתמש חבר בהן
  • extra: כל מידע נוסף על המשתמש שסופק על ידי Kubernetes
object האובייקט שהמשתמש מנסה לשנות או ליצור.
oldObject המצב המקורי של האובייקט. הערך הזה זמין רק בפעולות UPDATE.
dryRun האם הבקשה הזו הופעלה באמצעות kubectl --dry-run. הערך הזה לא זמין במהלך ביקורת.

כתיבה של תבניות אילוצים הפניות

תבניות של אילוצים הפנייתיים הן תבניות שמאפשרות למשתמש להגביל אובייקט אחד ביחס לאובייקטים אחרים. לדוגמה, 'לא לאפשר יצירת Pod לפני שמתגלה Ingress תואם'. דוגמה נוספת: "אסור לאפשר לשני שירותים להיות בעלי אותו שם מארח".

באמצעות Policy Controller אפשר לכתוב אילוצים רפרנציאליים על ידי מעקב אחרי שרת ה-API עבור קבוצת משאבים שסופקה על ידי המשתמש. כשמשנים משאב, Policy Controller שומר אותו במטמון באופן מקומי כדי שאפשר יהיה להפנות אליו בקלות מקוד המקור של Rego. Policy Controller מאפשר גישה למטמון הזה באמצעות מילת המפתח data.inventory.

משאבים בהיקף אשכול נשמרים במטמון במיקום הבא:

data.inventory.cluster["GROUP_VERSION"]["KIND"]["NAME"]

לדוגמה, צומת בשם my-favorite-node יכול להימצא בקטע

data.inventory.cluster["v1"]["Node"]["my-favorite-node"]

משאבים בהיקף מרחב השמות נשמרים במטמון כאן:

data.inventory.namespace["NAMESPACE"]["GROUP_VERSION"]["KIND"]["NAME"]

לדוגמה, אפשר למצוא ConfigMap בשם production-variables במרחב השמות shipping-prod בנתיב

data.inventory.namespace["shipping-prod"]["v1"]["ConfigMap"]["production-variables"]

התוכן המלא של האובייקט מאוחסן במיקום הזה במטמון, ואפשר להפנות אליו בקוד המקור של Rego בכל דרך שמתאימה לכם.

מידע נוסף על Rego

המידע שלמעלה מתאר את התכונות הייחודיות של Policy Controller, שמקלות על כתיבת אילוצים על משאבי Kubernetes ב-Rego. המדריך הזה לא כולל הדרכה מלאה על כתיבה ב-Rego. עם זאת, במסמכי התיעוד של Open Policy Agent יש מידע על התחביר והתכונות של שפת Rego עצמה.

התקנה של תבנית האילוצים

אחרי שיוצרים תבנית אילוץ, משתמשים ב-kubectl apply כדי להחיל אותה, ו-Policy Controller דואג להטמעה שלה. חשוב לבדוק את השדה status בתבנית האילוץ כדי לוודא שלא היו שגיאות בהפעלת התבנית. אם ההעלאה תצליח, בשדה status יוצג הערך created: true, והערך observedGeneration שצוין בשדה status יהיה שווה לערך בשדה metadata.generation.

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

הסרה של תבנית אילוצים

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

  1. מוודאים שאף אילוץ שרוצים לשמור לא משתמש בתבנית האילוצים:

    kubectl get TEMPLATE_NAME
    

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

    kubectl get TEMPLATE_NAME.constraints.gatekeeper.sh
    
  2. מסירים את תבנית האילוצים:

    kubectl delete constrainttemplate CONSTRAINT_TEMPLATE_NAME
    

כשמסירים תבנית אילוצים, אי אפשר יותר ליצור אילוצים שמפנים אליה.

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